From 5db9d7cd23a64cd5465259bc338ba09f6cb86dee Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 2 Sep 2024 09:59:01 -0400 Subject: [PATCH] Move CollectionUtils.duplicates() to IterableUtils - Update input type from Collection to Iterable - The CollectionUtils duplicate methods are actually general enough to work with Iterable --- .../commons/collections4/CollectionUtils.java | 57 -------- .../commons/collections4/IterableUtils.java | 58 ++++++++ .../collections4/CollectionUtilsTest.java | 134 ------------------ .../collections4/IterableUtilsTest.java | 134 ++++++++++++++++++ 4 files changed, 192 insertions(+), 191 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index ff53f36dca..3aed6feae5 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -25,7 +25,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -762,62 +761,6 @@ public static Collection disjunction(final Iterable a, final return helper.list(); } - /** - * Finds and returns the List of duplicate elements in the given collection. - * - * @param the type of elements in the collection. - * @param collection the list to test, must not be null. - * @return the set of duplicate elements, may be empty. - * @since 4.5.0-M3 - */ - public static List duplicateList(final Collection collection) { - return new ArrayList<>(duplicateSet(collection)); - } - - /** - * Finds and returns the sequenced Set of duplicate elements in the given collection. - *

- * Once we are on Java 21 and a new major version, the return type should be SequencedSet. - *

- * - * @param the type of elements in the collection. - * @param collection the list to test, must not be null. - * @return the set of duplicate elements, may be empty. - * @since 4.5.0-M3 - */ - public static Set duplicateSequencedSet(final Collection collection) { - return duplicateSet(collection, new LinkedHashSet<>()); - } - - /** - * Finds and returns the set of duplicate elements in the given collection. - * - * @param the type of elements in the collection. - * @param collection the list to test, must not be null. - * @return the set of duplicate elements, may be empty. - * @since 4.5.0-M3 - */ - public static Set duplicateSet(final Collection collection) { - return duplicateSet(collection, new HashSet<>()); - } - - /** - * Worker method for {@link #duplicateSet(Collection)} and friends. - * - * @param the type of Collection. - * @param the type of elements in the Collection. - * @param collection the list to test, must not be null. - * @param duplicates the list to test, must not be null. - * @return the set of duplicate elements, may be empty. - */ - static , E> C duplicateSet(final Collection collection, final C duplicates) { - final Set set = new HashSet<>(); - for (final E e : collection) { - (set.contains(e) ? duplicates : set).add(e); - } - return duplicates; - } - /** * Returns the immutable EMPTY_COLLECTION with generic type safety. * diff --git a/src/main/java/org/apache/commons/collections4/IterableUtils.java b/src/main/java/org/apache/commons/collections4/IterableUtils.java index 7066028fff..0dc50453ae 100644 --- a/src/main/java/org/apache/commons/collections4/IterableUtils.java +++ b/src/main/java/org/apache/commons/collections4/IterableUtils.java @@ -20,7 +20,9 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import java.util.Set; @@ -345,6 +347,62 @@ public static long countMatches(final Iterable input, final Predicate the type of elements in the collection. + * @param iterable the list to test, must not be null. + * @return the set of duplicate elements, may be empty. + * @since 4.5.0-M3 + */ + public static List duplicateList(final Iterable iterable) { + return new ArrayList<>(duplicateSet(iterable)); + } + + /** + * Finds and returns the sequenced Set of duplicate elements in the given collection. + *

+ * Once we are on Java 21 and a new major version, the return type should be SequencedSet. + *

+ * + * @param the type of elements in the collection. + * @param iterable the list to test, must not be null. + * @return the set of duplicate elements, may be empty. + * @since 4.5.0-M3 + */ + public static Set duplicateSequencedSet(final Iterable iterable) { + return duplicateSet(iterable, new LinkedHashSet<>()); + } + + /** + * Finds and returns the set of duplicate elements in the given collection. + * + * @param the type of elements in the collection. + * @param iterable the list to test, must not be null. + * @return the set of duplicate elements, may be empty. + * @since 4.5.0-M3 + */ + public static Set duplicateSet(final Iterable iterable) { + return duplicateSet(iterable, new HashSet<>()); + } + + /** + * Worker method for {@link #duplicateSet(Collection)} and friends. + * + * @param the type of Collection. + * @param the type of elements in the Collection. + * @param iterable the list to test, must not be null. + * @param duplicates the list to test, must not be null. + * @return the set of duplicate elements, may be empty. + */ + static , E> C duplicateSet(final Iterable iterable, final C duplicates) { + final Set set = new HashSet<>(); + for (final E e : iterable) { + (set.contains(e) ? duplicates : set).add(e); + } + return duplicates; + } + /** * Returns an immutable empty iterable if the argument is null, * or the argument itself otherwise. diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index cb507a0ecb..e1c2f206a4 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -27,20 +27,17 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Deque; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -876,137 +873,6 @@ public void testDisjunctionNullColl2() { assertThrows(NullPointerException.class, () -> CollectionUtils.disjunction(list, null)); } - @Test - public void testDuplicateListAllSameInList() { - final List input = Arrays.asList(5, 5, 5, 5); - assertEquals(Arrays.asList(5), CollectionUtils.duplicateList(input)); - } - - @Test - public void testDuplicateListEmptyDeque() { - assertTrue(CollectionUtils.duplicateList(new ArrayDeque<>()).isEmpty()); - } - - @Test - public void testDuplicateListEmptyList() { - final List input = Arrays.asList(); - assertTrue(CollectionUtils.duplicateList(input).isEmpty()); - } - - @Test - public void testDuplicateListEmptySet() { - assertTrue(CollectionUtils.duplicateList(new HashSet<>()).isEmpty()); - } - - @Test - public void testDuplicateListMultipleDuplicatesInDeque() { - final Deque input = new ArrayDeque<>(Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4)); - final List expected = Arrays.asList(1, 2, 3, 4); - assertEquals(expected, CollectionUtils.duplicateList(input)); - } - - @Test - public void testDuplicateListMultipleDuplicatesInList() { - final List input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4); - final List expected = Arrays.asList(1, 2, 3, 4); - assertEquals(expected, CollectionUtils.duplicateList(input)); - } - - @Test - public void testDuplicateListNoDuplicates() { - final List input = Arrays.asList(1, 2, 3, 4, 5); - assertTrue(CollectionUtils.duplicateList(input).isEmpty()); - } - - @Test - public void testDuplicateListSingleElement() { - final List input = Arrays.asList(1); - assertTrue(CollectionUtils.duplicateList(input).isEmpty()); - } - - @Test - public void testDuplicateListWithDuplicates() { - final List input = Arrays.asList(1, 2, 3, 2, 4, 5, 3); - final List expected = Arrays.asList(2, 3); - assertEquals(expected, CollectionUtils.duplicateList(input)); - } - - @Test - public void testDuplicateSequencedSetMultipleDuplicates() { - final List input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4); - final List list = Arrays.asList(1, 2, 3, 4); - assertEquals(list, new ArrayList<>(CollectionUtils.duplicateSequencedSet(input))); - assertEquals(new LinkedHashSet<>(list), CollectionUtils.duplicateSequencedSet(input)); - } - - @Test - public void testDuplicateSetEmptyDeque() { - assertTrue(CollectionUtils.duplicateSet(new ArrayDeque<>()).isEmpty()); - } - - @Test - public void testDuplicateSetEmptyList() { - final List input = Arrays.asList(); - assertTrue(CollectionUtils.duplicateSet(input).isEmpty()); - } - - @Test - public void testDuplicateSetEmptySet() { - assertTrue(CollectionUtils.duplicateSet(new HashSet<>()).isEmpty()); - } - - @Test - public void testDuplicateSetInSet() { - // Sets don't have duplicates, so the result is always an empty set. - final Set input = new HashSet<>(Arrays.asList(5)); - assertTrue(CollectionUtils.duplicateSet(input).isEmpty()); - } - - @Test - public void testDuplicateSetMultipleDuplicatesInDeque() { - final Deque input = new ArrayDeque<>(Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4)); - final Set expected = new HashSet<>(Arrays.asList(1, 2, 3, 4)); - assertEquals(expected, CollectionUtils.duplicateSet(input)); - } - - @Test - public void testDuplicateSetMultipleDuplicatesInList() { - final List input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4); - final Set expected = new HashSet<>(Arrays.asList(1, 2, 3, 4)); - assertEquals(expected, CollectionUtils.duplicateSet(input)); - } - - @Test - public void testDuplicateSetNoDuplicates() { - final List input = Arrays.asList(1, 2, 3, 4, 5); - assertTrue(CollectionUtils.duplicateSet(input).isEmpty()); - } - - @Test - public void testDuplicateSetSingleElement() { - final List input = Arrays.asList(1); - assertTrue(CollectionUtils.duplicateSet(input).isEmpty()); - } - - @Test - public void testDuplicateSetWithDuplicates() { - final List input = Arrays.asList(1, 2, 3, 2, 4, 5, 3); - final Set expected = new HashSet<>(Arrays.asList(2, 3)); - assertEquals(expected, CollectionUtils.duplicateSet(input)); - } - - @Test - public void testDuplicatListAllSameInDeque() { - final Deque input = new ArrayDeque<>(Arrays.asList(5, 5, 5, 5)); - assertEquals(Arrays.asList(5), CollectionUtils.duplicateList(input)); - } - - @Test - public void testDuplicatSetAllSameInDeque() { - final Deque input = new ArrayDeque<>(Arrays.asList(5, 5, 5, 5)); - assertEquals(new HashSet<>(Arrays.asList(5)), CollectionUtils.duplicateSet(input)); - } - @Test public void testEmptyCollection() throws Exception { final Collection coll = CollectionUtils.emptyCollection(); diff --git a/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java b/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java index 94ea67884f..b1de8d9185 100644 --- a/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java @@ -27,11 +27,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Deque; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -153,6 +156,137 @@ public void testCountMatches() { ); } + @Test + public void testDuplicateListAllSameInList() { + final List input = Arrays.asList(5, 5, 5, 5); + assertEquals(Arrays.asList(5), IterableUtils.duplicateList(input)); + } + + @Test + public void testDuplicateListEmptyDeque() { + assertTrue(IterableUtils.duplicateList(new ArrayDeque<>()).isEmpty()); + } + + @Test + public void testDuplicateListEmptyList() { + final List input = Arrays.asList(); + assertTrue(IterableUtils.duplicateList(input).isEmpty()); + } + + @Test + public void testDuplicateListEmptySet() { + assertTrue(IterableUtils.duplicateList(new HashSet<>()).isEmpty()); + } + + @Test + public void testDuplicateListMultipleDuplicatesInDeque() { + final Deque input = new ArrayDeque<>(Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4)); + final List expected = Arrays.asList(1, 2, 3, 4); + assertEquals(expected, IterableUtils.duplicateList(input)); + } + + @Test + public void testDuplicateListMultipleDuplicatesInList() { + final List input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4); + final List expected = Arrays.asList(1, 2, 3, 4); + assertEquals(expected, IterableUtils.duplicateList(input)); + } + + @Test + public void testDuplicateListNoDuplicates() { + final List input = Arrays.asList(1, 2, 3, 4, 5); + assertTrue(IterableUtils.duplicateList(input).isEmpty()); + } + + @Test + public void testDuplicateListSingleElement() { + final List input = Arrays.asList(1); + assertTrue(IterableUtils.duplicateList(input).isEmpty()); + } + + @Test + public void testDuplicateListWithDuplicates() { + final List input = Arrays.asList(1, 2, 3, 2, 4, 5, 3); + final List expected = Arrays.asList(2, 3); + assertEquals(expected, IterableUtils.duplicateList(input)); + } + + @Test + public void testDuplicateSequencedSetMultipleDuplicates() { + final List input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4); + final List list = Arrays.asList(1, 2, 3, 4); + assertEquals(list, new ArrayList<>(IterableUtils.duplicateSequencedSet(input))); + assertEquals(new LinkedHashSet<>(list), IterableUtils.duplicateSequencedSet(input)); + } + + @Test + public void testDuplicateSetEmptyDeque() { + assertTrue(IterableUtils.duplicateSet(new ArrayDeque<>()).isEmpty()); + } + + @Test + public void testDuplicateSetEmptyList() { + final List input = Arrays.asList(); + assertTrue(IterableUtils.duplicateSet(input).isEmpty()); + } + + @Test + public void testDuplicateSetEmptySet() { + assertTrue(IterableUtils.duplicateSet(new HashSet<>()).isEmpty()); + } + + @Test + public void testDuplicateSetInSet() { + // Sets don't have duplicates, so the result is always an empty set. + final Set input = new HashSet<>(Arrays.asList(5)); + assertTrue(IterableUtils.duplicateSet(input).isEmpty()); + } + + @Test + public void testDuplicateSetMultipleDuplicatesInDeque() { + final Deque input = new ArrayDeque<>(Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4)); + final Set expected = new HashSet<>(Arrays.asList(1, 2, 3, 4)); + assertEquals(expected, IterableUtils.duplicateSet(input)); + } + + @Test + public void testDuplicateSetMultipleDuplicatesInList() { + final List input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4); + final Set expected = new HashSet<>(Arrays.asList(1, 2, 3, 4)); + assertEquals(expected, IterableUtils.duplicateSet(input)); + } + + @Test + public void testDuplicateSetNoDuplicates() { + final List input = Arrays.asList(1, 2, 3, 4, 5); + assertTrue(IterableUtils.duplicateSet(input).isEmpty()); + } + + @Test + public void testDuplicateSetSingleElement() { + final List input = Arrays.asList(1); + assertTrue(IterableUtils.duplicateSet(input).isEmpty()); + } + + @Test + public void testDuplicateSetWithDuplicates() { + final List input = Arrays.asList(1, 2, 3, 2, 4, 5, 3); + final Set expected = new HashSet<>(Arrays.asList(2, 3)); + assertEquals(expected, IterableUtils.duplicateSet(input)); + } + + @Test + public void testDuplicatListAllSameInDeque() { + final Deque input = new ArrayDeque<>(Arrays.asList(5, 5, 5, 5)); + assertEquals(Arrays.asList(5), IterableUtils.duplicateList(input)); + } + + @Test + public void testDuplicatSetAllSameInDeque() { + final Deque input = new ArrayDeque<>(Arrays.asList(5, 5, 5, 5)); + assertEquals(new HashSet<>(Arrays.asList(5)), IterableUtils.duplicateSet(input)); + } + @Test public void testFind() { Predicate testPredicate = equalPredicate(4);