Add CollectionUtils.duplicate[List|Set]

- Add CollectionUtils.duplicateList(Collection<E>)
- Add CollectionUtils.duplicateSequencedSet(Collection<E>)
- Add CollectionUtils.duplicateSet(Collection<E>)
This commit is contained in:
Gary Gregory 2024-09-01 11:01:45 -04:00
parent fa76c00a4f
commit 77faa5be8f
3 changed files with 194 additions and 0 deletions

View File

@ -37,6 +37,9 @@
<action type="fix" dev="ggregory" due-to="Dávid Szigecsán">Use the Junit (Jupiter) API #518.</action>
<!-- ADD -->
<action type="add" dev="ggregory" due-to="Dávid Szigecsán">LayerManager.Builder implements Supplier.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory, hemanth0525">Add CollectionUtils.duplicateList(Collection).</action>
<action type="add" dev="ggregory" due-to="Gary Gregory, hemanth0525">Add CollectionUtils.duplicateSet(Collection).</action>
<action type="add" dev="ggregory" due-to="Gary Gregory, hemanth0525">Add CollectionUtils.duplicateSequencedSet(Collection).</action>
<!-- UPDATE -->
<action issue="COLLECTIONS-857" type="update" dev="ggregory" due-to="Claude Warren">Update bloom filter documentation #508.</action>
<action issue="COLLECTIONS-857" type="update" dev="ggregory" due-to="Dependabot, Gary Gregory">Bump commons-codec:commons-codec from 1.17.0 to 1.17.1 #514.</action>

View File

@ -25,6 +25,7 @@ import java.util.Enumeration;
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;
@ -756,6 +757,62 @@ public class CollectionUtils {
return helper.list();
}
/**
* Finds and returns the List of duplicate elements in the given collection.
*
* @param <E> 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 <E> List<E> duplicateList(final Collection<E> collection) {
return new ArrayList<>(duplicateSet(collection));
}
/**
* Finds and returns the sequenced Set of duplicate elements in the given collection.
* <p>
* Once we are on Java 21 and a new major version, the return type should be SequencedSet.
* </p>
*
* @param <E> 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 <E> Set<E> duplicateSequencedSet(final Collection<E> collection) {
return duplicateSet(collection, new LinkedHashSet<>());
}
/**
* Finds and returns the set of duplicate elements in the given collection.
*
* @param <E> 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 <E> Set<E> duplicateSet(final Collection<E> collection) {
return duplicateSet(collection, new HashSet<>());
}
/**
* Worker method for {@link #duplicateSet(Collection)} and friends.
*
* @param <C> the type of Collection.
* @param <E> 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 <C extends Collection<E>, E> C duplicateSet(final Collection<E> collection, final C duplicates) {
final Set<E> 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.
*

View File

@ -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<Integer> 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<Integer> input = Arrays.asList();
assertTrue(CollectionUtils.duplicateList(input).isEmpty());
}
@Test
public void testDuplicateListEmptySet() {
assertTrue(CollectionUtils.duplicateList(new HashSet<>()).isEmpty());
}
@Test
public void testDuplicateListMultipleDuplicatesInDeque() {
final Deque<Integer> input = new ArrayDeque<>(Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4));
final List<Integer> expected = Arrays.asList(1, 2, 3, 4);
assertEquals(expected, CollectionUtils.duplicateList(input));
}
@Test
public void testDuplicateListMultipleDuplicatesInList() {
final List<Integer> input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4);
final List<Integer> expected = Arrays.asList(1, 2, 3, 4);
assertEquals(expected, CollectionUtils.duplicateList(input));
}
@Test
public void testDuplicateListNoDuplicates() {
final List<Integer> input = Arrays.asList(1, 2, 3, 4, 5);
assertTrue(CollectionUtils.duplicateList(input).isEmpty());
}
@Test
public void testDuplicateListSingleElement() {
final List<Integer> input = Arrays.asList(1);
assertTrue(CollectionUtils.duplicateList(input).isEmpty());
}
@Test
public void testDuplicateListWithDuplicates() {
final List<Integer> input = Arrays.asList(1, 2, 3, 2, 4, 5, 3);
final List<Integer> expected = Arrays.asList(2, 3);
assertEquals(expected, CollectionUtils.duplicateList(input));
}
@Test
public void testDuplicateSequencedSetMultipleDuplicates() {
final List<Integer> input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4);
final List<Integer> 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<Integer> 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<Integer> input = new HashSet<>(Arrays.asList(5));
assertTrue(CollectionUtils.duplicateSet(input).isEmpty());
}
@Test
public void testDuplicateSetMultipleDuplicatesInDeque() {
final Deque<Integer> input = new ArrayDeque<>(Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4));
final Set<Integer> expected = new HashSet<>(Arrays.asList(1, 2, 3, 4));
assertEquals(expected, CollectionUtils.duplicateSet(input));
}
@Test
public void testDuplicateSetMultipleDuplicatesInList() {
final List<Integer> input = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4);
final Set<Integer> expected = new HashSet<>(Arrays.asList(1, 2, 3, 4));
assertEquals(expected, CollectionUtils.duplicateSet(input));
}
@Test
public void testDuplicateSetNoDuplicates() {
final List<Integer> input = Arrays.asList(1, 2, 3, 4, 5);
assertTrue(CollectionUtils.duplicateSet(input).isEmpty());
}
@Test
public void testDuplicateSetSingleElement() {
final List<Integer> input = Arrays.asList(1);
assertTrue(CollectionUtils.duplicateSet(input).isEmpty());
}
@Test
public void testDuplicateSetWithDuplicates() {
final List<Integer> input = Arrays.asList(1, 2, 3, 2, 4, 5, 3);
final Set<Integer> expected = new HashSet<>(Arrays.asList(2, 3));
assertEquals(expected, CollectionUtils.duplicateSet(input));
}
@Test
public void testDuplicatListAllSameInDeque() {
final Deque<Integer> input = new ArrayDeque<>(Arrays.asList(5, 5, 5, 5));
assertEquals(Arrays.asList(5), CollectionUtils.duplicateList(input));
}
@Test
public void testDuplicatSetAllSameInDeque() {
final Deque<Integer> 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<Number> coll = CollectionUtils.emptyCollection();