diff --git a/primitiveCollections/src/main/java/org/lucares/collections/IntList.java b/primitiveCollections/src/main/java/org/lucares/collections/IntList.java index 8af241a..42565c3 100644 --- a/primitiveCollections/src/main/java/org/lucares/collections/IntList.java +++ b/primitiveCollections/src/main/java/org/lucares/collections/IntList.java @@ -54,7 +54,9 @@ public final class IntList implements Serializable, Cloneable { /** * Keeps track of whether or not the list is sorted. This allows us to use - * binary search for {@link #indexOf(int)}. An empty list is sorted. + * binary search for {@link #indexOf(int)} and efficient algorithms for + * {@link #intersection(IntList, IntList)} / {@link #union(IntList, IntList)} / + * {@link #uniq()} / {@link #removeAll(int, int)}. An empty list is sorted. */ private boolean sorted = true; @@ -680,6 +682,38 @@ public final class IntList implements Serializable, Cloneable { checkIfSorted(); } + /** + * Removes all duplicate values from the list. The list will be sorted if it is + * not already sorted. + * + * The list can have unused capacity. Consider using {@link #trim()}. + */ + public void uniq() { + if (size <= 1) { + // nothing to do + return; + } + if (!sorted) { + sort(); + } + uniqSorted(); + } + + private void uniqSorted() { + int insertPosition = 1; + int prev = data[0]; + for (int i = 1; i < size; i++) { + final int current = data[i]; + + if (prev != current) { + data[insertPosition] = current; + insertPosition++; + prev = current; + } + } + size = insertPosition; + } + private void ensureCapacity(final int newElements) { final int requiredCapacity = size + newElements; diff --git a/primitiveCollections/src/main/java/org/lucares/collections/LongList.java b/primitiveCollections/src/main/java/org/lucares/collections/LongList.java index 87b2125..1ee609d 100644 --- a/primitiveCollections/src/main/java/org/lucares/collections/LongList.java +++ b/primitiveCollections/src/main/java/org/lucares/collections/LongList.java @@ -39,7 +39,10 @@ public final class LongList implements Serializable, Cloneable { /** * Keeps track of whether or not the list is sorted. This allows us to use - * binary search for {@link #indexOf(int)}. An empty list is sorted. + * binary search for {@link #indexOf(int)} and efficient algorithms for + * {@link #intersection(LongList, LongList)} / + * {@link #union(LongList, LongList)} / {@link #uniq()} / + * {@link #removeAll(int, int)}. An empty list is sorted. */ private boolean sorted = true; @@ -685,6 +688,38 @@ public final class LongList implements Serializable, Cloneable { checkIfSorted(); } + /** + * Removes all duplicate values from the list. The list will be sorted if it is + * not already sorted. + * + * The list can have unused capacity. Consider using {@link #trim()}. + */ + public void uniq() { + if (size <= 1) { + // nothing to do + return; + } + if (!sorted) { + sort(); + } + uniqSorted(); + } + + private void uniqSorted() { + int insertPosition = 1; + long prev = data[0]; + for (int i = 1; i < size; i++) { + final long current = data[i]; + + if (prev != current) { + data[insertPosition] = current; + insertPosition++; + prev = current; + } + } + size = insertPosition; + } + private void ensureCapacity(final int newElements) { final int requiredCapacity = size + newElements; @@ -1182,4 +1217,5 @@ public final class LongList implements Serializable, Cloneable { sorted = data[i - 1] <= data[i]; } } + } diff --git a/primitiveCollections/src/test/java/org/lucares/collections/IntListTest.java b/primitiveCollections/src/test/java/org/lucares/collections/IntListTest.java index 57fc3fa..c124506 100644 --- a/primitiveCollections/src/test/java/org/lucares/collections/IntListTest.java +++ b/primitiveCollections/src/test/java/org/lucares/collections/IntListTest.java @@ -1635,4 +1635,41 @@ public class IntListTest { Assertions.assertEquals(IntList.of(1, 2, 3, 4, 5), actual); Assertions.assertEquals(IntList.union(a, b), IntList.union(b, a)); } + + @Test + public void testUniq_sorted() { + final IntList sorted = IntList.of(1, 1, 2, 3, 4, 4, 4); + final IntList expected = IntList.of(1, 2, 3, 4); + + sorted.uniq(); + Assertions.assertEquals(expected, sorted); + } + + @Test + public void testUniq_empty() { + final IntList empty = IntList.of(); + final IntList expected = IntList.of(); + + empty.uniq(); + Assertions.assertEquals(expected, empty); + } + + @Test + public void testUniq_oneElement() { + final IntList list = IntList.of(1); + final IntList expected = IntList.of(1); + + list.uniq(); + Assertions.assertEquals(expected, list); + } + + @Test + public void testUniq_unsorted() { + final IntList unsorted = IntList.of(1, 1, 2, 3, 4, 4, 4); + unsorted.shuffle(); + final IntList expected = IntList.of(1, 2, 3, 4); + + unsorted.uniq(); + Assertions.assertEquals(expected, unsorted); + } } diff --git a/primitiveCollections/src/test/java/org/lucares/collections/LongListTest.java b/primitiveCollections/src/test/java/org/lucares/collections/LongListTest.java index 978464a..49ae966 100644 --- a/primitiveCollections/src/test/java/org/lucares/collections/LongListTest.java +++ b/primitiveCollections/src/test/java/org/lucares/collections/LongListTest.java @@ -1625,4 +1625,41 @@ public class LongListTest { Assertions.assertEquals(LongList.of(1, 2, 3, 4, 5), actual); Assertions.assertEquals(LongList.union(a, b), LongList.union(b, a)); } + + @Test + public void testUniq_sorted() { + final LongList sorted = LongList.of(1, 1, 2, 3, 4, 4, 4); + final LongList expected = LongList.of(1, 2, 3, 4); + + sorted.uniq(); + Assertions.assertEquals(expected, sorted); + } + + @Test + public void testUniq_empty() { + final LongList empty = LongList.of(); + final LongList expected = LongList.of(); + + empty.uniq(); + Assertions.assertEquals(expected, empty); + } + + @Test + public void testUniq_oneElement() { + final LongList list = LongList.of(1); + final LongList expected = LongList.of(1); + + list.uniq(); + Assertions.assertEquals(expected, list); + } + + @Test + public void testUniq_unsorted() { + final LongList unsorted = LongList.of(1, 1, 2, 3, 4, 4, 4); + unsorted.shuffle(); + final LongList expected = LongList.of(1, 2, 3, 4); + + unsorted.uniq(); + Assertions.assertEquals(expected, unsorted); + } }