add union(IntList,IntList) and addAll(IntList)
IntPredicate gets the current value and the index. This was handy while removing duplicate values.
This commit is contained in:
@@ -21,7 +21,14 @@ public final class IntList implements Serializable, Cloneable {
|
||||
// TODO add mod counts
|
||||
// TODO support sublists
|
||||
// TODO add lastIndexOf
|
||||
// TODO check that methods like intersection/union work with big arrays. They
|
||||
// should not try to allocate more memory MAX_ARRAY_SIZE
|
||||
// TODO remove bounds checks that are handled by java, e.g. negative indices
|
||||
// TODO removeIf see ArrayList.removeIf. Cannot handle removeIf(i -> indexOf(i)
|
||||
// != lastIndexOf(i)) on sorted lists
|
||||
// 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.
|
||||
|
||||
private static final long serialVersionUID = 2622570032686034909L;
|
||||
|
||||
@@ -81,9 +88,8 @@ public final class IntList implements Serializable, Cloneable {
|
||||
* if the specified {@link IntList} is null
|
||||
*/
|
||||
public IntList(final IntList intList) {
|
||||
data = Arrays.copyOf(intList.data, intList.size());
|
||||
size = intList.size();
|
||||
sorted = intList.sorted;
|
||||
data = EMPTY_ARRAY;
|
||||
addAll(intList);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,6 +267,36 @@ public final class IntList implements Serializable, Cloneable {
|
||||
size += values.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all value of the given list.
|
||||
*
|
||||
* @param list
|
||||
* the list
|
||||
* @throws NullPointerException
|
||||
* if the given list is null
|
||||
*/
|
||||
public void addAll(final IntList list) {
|
||||
ensureCapacity(list.size());
|
||||
|
||||
System.arraycopy(list.data, 0, data, size, list.size());
|
||||
|
||||
if (sorted) {
|
||||
sorted = list.isSorted();
|
||||
if (list.isSorted() // new list is sorted
|
||||
&& !isEmpty() // if old list is empty, then the new list's sorted value is equal to that of
|
||||
// the new list
|
||||
&& !list.isEmpty()) // if new list is empty, then old list stays sorted
|
||||
{
|
||||
// check that the first new value is bigger than the highest old value
|
||||
final int highestOldValue = data[size - 1]; // size has still the old value
|
||||
final int lowestNewValue = list.get(0);
|
||||
sorted = highestOldValue <= lowestNewValue;
|
||||
}
|
||||
}
|
||||
|
||||
size += list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes elements from the list.
|
||||
* <p>
|
||||
@@ -344,7 +380,7 @@ public final class IntList implements Serializable, Cloneable {
|
||||
int insertPosition = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
final int current = data[i];
|
||||
if (!predicate.test(current)) {
|
||||
if (!predicate.test(current, i)) {
|
||||
// keep current element
|
||||
data[insertPosition] = current;
|
||||
insertPosition++;
|
||||
@@ -598,8 +634,8 @@ public final class IntList implements Serializable, Cloneable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first occurrence of {@code value} starting at the
|
||||
* {@code offset}'s element, or -1 if it does not exist.
|
||||
* Returns the index of the last occurrence of {@code value}, or -1 if it does
|
||||
* not exist.
|
||||
* <p>
|
||||
* This method uses a binary search algorithm if the list is sorted.
|
||||
*
|
||||
@@ -610,6 +646,8 @@ public final class IntList implements Serializable, Cloneable {
|
||||
* @return the index, or -1
|
||||
* @throws ArrayIndexOutOfBoundsException
|
||||
* if offset is negative, or larger than the size of the list
|
||||
* @throws IllegalArgumentException
|
||||
* if offset is negative
|
||||
* @see #isSorted()
|
||||
*/
|
||||
public int indexOf(final int value, final int offset) {
|
||||
@@ -617,7 +655,7 @@ public final class IntList implements Serializable, Cloneable {
|
||||
int result = -1;
|
||||
if (sorted) {
|
||||
int insertionPoint = Arrays.binarySearch(data, offset, size(), value);
|
||||
while (insertionPoint > 0 && insertionPoint > offset && data[insertionPoint - 1] == value) {
|
||||
while (insertionPoint > offset && data[insertionPoint - 1] == value) {
|
||||
insertionPoint--;
|
||||
}
|
||||
result = insertionPoint < 0 ? -1 : insertionPoint;
|
||||
@@ -760,12 +798,14 @@ public final class IntList implements Serializable, Cloneable {
|
||||
* method returns a new list. The list can have unused capacity. Consider using
|
||||
* {@link #trim()}.
|
||||
* <p>
|
||||
* If both lists were sorted, then the output list will also be sorted.
|
||||
* <p>
|
||||
* See {@link #retainAll(IntList)} for a method that modifies the list and keeps
|
||||
* duplicate values.
|
||||
* <p>
|
||||
* If both lists are sorted, then the complexity is O(n+m), where n is the
|
||||
* If both lists are sorted, then the time complexity is O(n+m), where n is the
|
||||
* length of the first list and m the length of the second list. If at least one
|
||||
* list is not sorted, then the complexity is O(n*log(m)), where n is the length
|
||||
* list is not sorted, then the time complexity is O(n*m), where n is the length
|
||||
* of the shorter list and m the length of the longer list.
|
||||
*
|
||||
* @param a
|
||||
@@ -834,8 +874,8 @@ public final class IntList implements Serializable, Cloneable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements an algorithm with O(n*log(m)), where n is the length of the
|
||||
* shorter list and m the length of the longer list.
|
||||
* Implements an algorithm with O(n*m), where n is the length of the shorter
|
||||
* list and m the length of the longer list.
|
||||
*
|
||||
* @param a
|
||||
* first list
|
||||
@@ -851,8 +891,6 @@ public final class IntList implements Serializable, Cloneable {
|
||||
if (aSize < bSize) {
|
||||
result = new IntList(Math.min(aSize, bSize));
|
||||
|
||||
assert !a.isSorted() || !b.isSorted() : "at least one list must be unsorted";
|
||||
|
||||
for (int l = 0; l < aSize; l++) {
|
||||
final int lv = a.get(l);
|
||||
|
||||
@@ -870,4 +908,104 @@ public final class IntList implements Serializable, Cloneable {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list with all elements that are in list {@code a} or {@code b}
|
||||
* (logical or).
|
||||
* <p>
|
||||
* The result does not contain duplicate values.
|
||||
* <p>
|
||||
* If both lists were sorted, then the output list will also be sorted. If at
|
||||
* least one list is unsorted, then the order is undefined.
|
||||
* <p>
|
||||
* If both lists are sorted, then the time complexity is O(n+m), where n is the
|
||||
* length of the first list and m the length of the second list. If at least one
|
||||
* list is not sorted, then the time complexity is O((n+m)*log(n+m)), where n is
|
||||
* the length of the shorter list and m the length of the longer list.
|
||||
*
|
||||
* @param a
|
||||
* the first list
|
||||
* @param b
|
||||
* the second list
|
||||
* @return the union of both lists
|
||||
*/
|
||||
public static IntList union(final IntList a, final IntList b) {
|
||||
final IntList result;
|
||||
|
||||
if (a.isSorted() && b.isSorted()) {
|
||||
result = unionSorted(a, b);
|
||||
} else {
|
||||
result = unionUnsorted(a, b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IntList unionSorted(final IntList a, final IntList b) {
|
||||
final IntList result = new IntList(a.size() + b.size());
|
||||
|
||||
final int aSize = a.size();
|
||||
final int bSize = b.size();
|
||||
|
||||
int l = 0;
|
||||
int r = 0;
|
||||
|
||||
while (l < a.size() && r < b.size()) {
|
||||
|
||||
final int lv = a.get(l);
|
||||
final int rv = b.get(r);
|
||||
|
||||
if (lv < rv) {
|
||||
result.add(lv);
|
||||
l++;
|
||||
while (l < aSize && lv == a.get(l)) {
|
||||
l++;
|
||||
}
|
||||
} else if (lv > rv) {
|
||||
result.add(rv);
|
||||
r++;
|
||||
while (r < bSize && rv == b.get(r)) {
|
||||
r++;
|
||||
}
|
||||
} else {
|
||||
result.add(lv);
|
||||
l++;
|
||||
r++;
|
||||
|
||||
while (l < aSize && lv == a.get(l)) {
|
||||
l++;
|
||||
}
|
||||
while (r < bSize && rv == b.get(r)) {
|
||||
r++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add remaining values from list a, if any exist
|
||||
for (; l < aSize; l++) {
|
||||
if (l == 0 || a.get(l) != a.get(l - 1)) {
|
||||
result.add(a.get(l));
|
||||
}
|
||||
}
|
||||
|
||||
// add remaining values from list b, if any exist
|
||||
for (; r < bSize; r++) {
|
||||
if (r == 0 || b.get(r) != b.get(r - 1)) {
|
||||
result.add(b.get(r));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IntList unionUnsorted(final IntList a, final IntList b) {
|
||||
// TODO use a more efficient algorithm. Especially the removeIf is too
|
||||
// expensive, because of all the method calls
|
||||
final IntList result;
|
||||
result = new IntList();
|
||||
result.addAll(a);
|
||||
result.addAll(b);
|
||||
result.sort();
|
||||
result.removeIf((value, index) -> index > 0 && result.get(index) == result.get(index - 1));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@ public interface IntPredicate {
|
||||
/**
|
||||
* Evaluates the predicate.
|
||||
*
|
||||
* @param i
|
||||
* the input argument
|
||||
* @param value
|
||||
* the value
|
||||
* @param index
|
||||
* the index in the list
|
||||
* @return {@code true} iff the input argument matches the predicate
|
||||
*/
|
||||
boolean test(int i);
|
||||
boolean test(int value, int index);
|
||||
|
||||
/**
|
||||
* Returns a predicate that represents the logical AND of {@code this} and
|
||||
@@ -28,7 +30,7 @@ public interface IntPredicate {
|
||||
* if {@code other} is null
|
||||
*/
|
||||
default IntPredicate and(final IntPredicate other) {
|
||||
return (t) -> test(t) && other.test(t);
|
||||
return (value, index) -> test(value, index) && other.test(value, index);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,7 +44,7 @@ public interface IntPredicate {
|
||||
* if {@code other} is null
|
||||
*/
|
||||
default IntPredicate or(final IntPredicate other) {
|
||||
return (t) -> test(t) || other.test(t);
|
||||
return (value, index) -> test(value, index) || other.test(value, index);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,6 +53,6 @@ public interface IntPredicate {
|
||||
* @return the negation of {@code this}
|
||||
*/
|
||||
default IntPredicate negate() {
|
||||
return (t) -> !test(t);
|
||||
return (value, index) -> !test(value, index);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user