add lastIndexOf
This commit is contained in:
@@ -29,6 +29,9 @@ public final class IntList implements Serializable, Cloneable {
|
||||
// TODO wrapper that reverses the order. This implies, that IntList becomes an
|
||||
// interface, or it could not be final anymore. Being an interface would make it
|
||||
// possible to have unmodifiable lists, too.
|
||||
// TODO memory optimization: add private method ensureExactCapacity, that does
|
||||
// not make the list 50% larger. This is useful for addAll or internal usage
|
||||
// where we know the exact size.
|
||||
|
||||
private static final long serialVersionUID = 2622570032686034909L;
|
||||
|
||||
@@ -634,7 +637,7 @@ public final class IntList implements Serializable, Cloneable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the last occurrence of {@code value}, or -1 if it does
|
||||
* Returns the index of the first occurrence of {@code value}, or -1 if it does
|
||||
* not exist.
|
||||
* <p>
|
||||
* This method uses a binary search algorithm if the list is sorted.
|
||||
@@ -642,7 +645,9 @@ public final class IntList implements Serializable, Cloneable {
|
||||
* @param value
|
||||
* the value
|
||||
* @param offset
|
||||
* the offset
|
||||
* the offset (inclusive). There is no invalid value. If the offset
|
||||
* is negative, then it behaves as if it was 0. If it is >=
|
||||
* {@link #size()}, then -1 is returned.
|
||||
* @return the index, or -1
|
||||
* @throws ArrayIndexOutOfBoundsException
|
||||
* if offset is negative, or larger than the size of the list
|
||||
@@ -653,14 +658,74 @@ public final class IntList implements Serializable, Cloneable {
|
||||
public int indexOf(final int value, final int offset) {
|
||||
|
||||
int result = -1;
|
||||
if (sorted) {
|
||||
if (sorted && offset >= 0 && offset < size()) {
|
||||
int insertionPoint = Arrays.binarySearch(data, offset, size(), value);
|
||||
while (insertionPoint > offset && data[insertionPoint - 1] == value) {
|
||||
insertionPoint--;
|
||||
}
|
||||
result = insertionPoint < 0 ? -1 : insertionPoint;
|
||||
} else {
|
||||
for (int i = offset; i < size; i++) {
|
||||
final int start = Math.max(offset, 0);
|
||||
for (int i = start; i < size; i++) {
|
||||
if (data[i] == value) {
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the last occurrence of {@code value} searching
|
||||
* backwards, or -1 if it does not exist.
|
||||
* <p>
|
||||
* This method uses a binary search algorithm if the list is sorted.
|
||||
*
|
||||
* @param value
|
||||
* the value
|
||||
* @return the index, or -1
|
||||
* @see #isSorted()
|
||||
*/
|
||||
public int lastIndexOf(final int value) {
|
||||
return lastIndexOf(value, size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the last occurrence of {@code value} searching backwards
|
||||
* from {@code fromIndex}, or -1 if it does not exist.
|
||||
* <p>
|
||||
* This method uses a binary search algorithm if the list is sorted.
|
||||
*
|
||||
* @param value
|
||||
* the value
|
||||
* @param fromIndex
|
||||
* the index the start the search from (inclusive). There is no
|
||||
* invalid input. If {@code fromIndex} is < 0, then -1 is
|
||||
* returned. If it is larger than the length of the list, then it
|
||||
* behaves as if it were {@link #size()}-1.
|
||||
* @return the index, or -1
|
||||
* @see #isSorted()
|
||||
*/
|
||||
public int lastIndexOf(final int value, final int fromIndex) {
|
||||
int result = -1;
|
||||
|
||||
if (sorted) {
|
||||
final int toIndex = Math.min(size - 1, fromIndex + 1); // toIndex is exclusive in binarySearch, but
|
||||
// fromIndex is inclusive
|
||||
if (toIndex > 0) {
|
||||
int insertionPoint = Arrays.binarySearch(data, 0, toIndex, value);
|
||||
|
||||
// if value exists more than once, then binarySearch can find any one of them,
|
||||
// but we are looking for the last occurrence
|
||||
while (insertionPoint >= 0 && insertionPoint < fromIndex && data[insertionPoint + 1] == value) {
|
||||
insertionPoint++;
|
||||
}
|
||||
result = insertionPoint < 0 ? -1 : insertionPoint;
|
||||
}
|
||||
} else {
|
||||
final int startIndex = Math.min(size - 1, fromIndex);
|
||||
for (int i = startIndex; i >= 0; i--) {
|
||||
if (data[i] == value) {
|
||||
result = i;
|
||||
break;
|
||||
|
||||
@@ -766,6 +766,14 @@ public class IntListTest {
|
||||
Assert.assertEquals(3, list.indexOf(3, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexOfWithOffsetOnSortedListWithOffsetOutOfRange() {
|
||||
final IntList list = new IntList();
|
||||
list.addAll(1);
|
||||
Assert.assertEquals(0, list.indexOf(1, -1));
|
||||
Assert.assertEquals(-1, list.indexOf(1, list.size()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexOfWithOffsetOnUnsortedList() {
|
||||
final IntList list = new IntList();
|
||||
@@ -783,6 +791,51 @@ public class IntListTest {
|
||||
Assert.assertEquals(list.get(list.indexOf(2, 3)), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLastIndexOfWithOffsetOnEmptyList() {
|
||||
final IntList list = IntList.of();
|
||||
|
||||
Assert.assertEquals(-1, list.lastIndexOf(3, list.size()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLastIndexOfWithOffsetOnSortedList() {
|
||||
final IntList list = IntList.of(1, 2, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
|
||||
Assert.assertEquals(3, list.lastIndexOf(3, list.size()));
|
||||
Assert.assertEquals(2, list.lastIndexOf(2, list.size()));
|
||||
Assert.assertEquals(0, list.lastIndexOf(1, list.size()));
|
||||
|
||||
Assert.assertEquals(2, list.lastIndexOf(2, 2)); // fromIndex == result
|
||||
Assert.assertEquals(1, list.lastIndexOf(2, 1)); // fromIndex == result && the next element would be a hit
|
||||
|
||||
Assert.assertEquals(0, list.lastIndexOf(1, 0)); // fromIndex 0; found
|
||||
Assert.assertEquals(-1, list.lastIndexOf(99, 0)); // fromIndex 0; not found
|
||||
Assert.assertEquals(-1, list.lastIndexOf(99, list.size())); // fromIndex larger than list && not found
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLastIndexOfOnSortedListReturnsFirstMatch() {
|
||||
final IntList list = IntList.of(0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4);
|
||||
Assert.assertEquals(13, list.lastIndexOf(2));
|
||||
Assert.assertEquals(10, list.lastIndexOf(2, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLastIndexOfWithOffsetOnUnsortedList() {
|
||||
final IntList list = IntList.of(1, 2, 3, 1, 2, 3);
|
||||
|
||||
Assert.assertEquals(5, list.lastIndexOf(3, list.size()));
|
||||
Assert.assertEquals(4, list.lastIndexOf(2, list.size()));
|
||||
Assert.assertEquals(3, list.lastIndexOf(1, list.size()));
|
||||
Assert.assertEquals(-1, list.lastIndexOf(99, list.size()));
|
||||
Assert.assertEquals(-1, list.lastIndexOf(99, 0));
|
||||
|
||||
Assert.assertEquals(2, list.lastIndexOf(3, list.size() - 2));
|
||||
Assert.assertEquals(4, list.lastIndexOf(2, list.size() - 1));
|
||||
Assert.assertEquals(1, list.lastIndexOf(2, list.lastIndexOf(2) - 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replaceAll() {
|
||||
final IntList list = new IntList();
|
||||
|
||||
Reference in New Issue
Block a user