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
|
// 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
|
// interface, or it could not be final anymore. Being an interface would make it
|
||||||
// possible to have unmodifiable lists, too.
|
// 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;
|
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.
|
* not exist.
|
||||||
* <p>
|
* <p>
|
||||||
* This method uses a binary search algorithm if the list is sorted.
|
* 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
|
* @param value
|
||||||
* the value
|
* the value
|
||||||
* @param offset
|
* @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
|
* @return the index, or -1
|
||||||
* @throws ArrayIndexOutOfBoundsException
|
* @throws ArrayIndexOutOfBoundsException
|
||||||
* if offset is negative, or larger than the size of the list
|
* 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) {
|
public int indexOf(final int value, final int offset) {
|
||||||
|
|
||||||
int result = -1;
|
int result = -1;
|
||||||
if (sorted) {
|
if (sorted && offset >= 0 && offset < size()) {
|
||||||
int insertionPoint = Arrays.binarySearch(data, offset, size(), value);
|
int insertionPoint = Arrays.binarySearch(data, offset, size(), value);
|
||||||
while (insertionPoint > offset && data[insertionPoint - 1] == value) {
|
while (insertionPoint > offset && data[insertionPoint - 1] == value) {
|
||||||
insertionPoint--;
|
insertionPoint--;
|
||||||
}
|
}
|
||||||
result = insertionPoint < 0 ? -1 : insertionPoint;
|
result = insertionPoint < 0 ? -1 : insertionPoint;
|
||||||
} else {
|
} 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) {
|
if (data[i] == value) {
|
||||||
result = i;
|
result = i;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -766,6 +766,14 @@ public class IntListTest {
|
|||||||
Assert.assertEquals(3, list.indexOf(3, 2));
|
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
|
@Test
|
||||||
public void testIndexOfWithOffsetOnUnsortedList() {
|
public void testIndexOfWithOffsetOnUnsortedList() {
|
||||||
final IntList list = new IntList();
|
final IntList list = new IntList();
|
||||||
@@ -783,6 +791,51 @@ public class IntListTest {
|
|||||||
Assert.assertEquals(list.get(list.indexOf(2, 3)), 2);
|
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
|
@Test
|
||||||
public void replaceAll() {
|
public void replaceAll() {
|
||||||
final IntList list = new IntList();
|
final IntList list = new IntList();
|
||||||
|
|||||||
Reference in New Issue
Block a user