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/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
index aaecfa991..811396067 100644
--- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
@@ -26,17 +26,20 @@ import static org.junit.jupiter.api.Assertions.assertSame;
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;
@@ -872,6 +875,137 @@ public class CollectionUtilsTest extends MockTestCase {
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();