From 1c79a12912e623fe61edafb4d89bbdac9f48ceee Mon Sep 17 00:00:00 2001 From: Ramanan Date: Mon, 29 Nov 2021 21:04:08 +0530 Subject: [PATCH 01/14] add partitionByChunkSize method in CollectionUtils --- pom.xml | 3 + .../commons/collections4/CollectionUtils.java | 55 +++++++++ .../collections4/CollectionUtilsTest.java | 108 +++++++++++++++++- 3 files changed, 165 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index def0a9c6b2..cb8415ca53 100644 --- a/pom.xml +++ b/pom.xml @@ -461,6 +461,9 @@ Arturo Bernal + + Ramanan Ravi + diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index f7d3e82111..0e0886ab61 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -2155,4 +2155,59 @@ public static E extractSingleton(final Collection collection) { } return collection.iterator().next(); } + + /** + * Returns partitions of given collection {@code collection}, each of size + * {@code chunkSize} (the final partition may be smaller). For example, + * partitioning a collection {@code collection} containing + * {@code [a, b, c, d, e, f, g]} with a chunkSize {@code chunkSize} of 3 yields + * an outer list {@link List} containing three collections of type + * {@code collection} where the first two collections will have three elements + * each and the final collection will have one element. Ordering of elements + * would be based on that of the {@link Iterator} of the given + * {@code collection}. + * + * @param the type of Collection + * @param collection the collection to be partitioned + * @param chunkSize the desired size of each partition (the last may be + * smaller) + * @return a list of collections (type as that of given input collection) + * @throws NullPointerException if the input collection is null + * @throws IllegalArgumentException if the input collection is empty + * @throws IllegalArgumentException if the input chunkSize is lesser than or + * equal to 0 + * @throws IllegalArgumentException if new instance of input collection cannot + * be instantiated + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static List partitionByChunkSize(final E collection, int chunkSize) { + Objects.requireNonNull(collection, "input collection must not be null"); + if (collection.size() == 0) { + throw new IllegalArgumentException("input collection must not be empty"); + } + if (chunkSize <= 0) { + throw new IllegalArgumentException("input chunk size must be greater than 0"); + } + List returnList = new ArrayList<>(); + Iterator iterator = collection.iterator(); + int counter = chunkSize; + try { + E tempCollection = (E) collection.getClass().newInstance(); + while (iterator.hasNext()) { + tempCollection.add(iterator.next()); + counter--; + if (counter == 0) { + returnList.add(tempCollection); + tempCollection = (E) collection.getClass().newInstance(); + counter = chunkSize; + } + } + if (tempCollection.size() > 0) { + returnList.add(tempCollection); + } + } catch (IllegalAccessException | InstantiationException e) { + throw new IllegalArgumentException("unable to get instance of given input collection"); + } + return returnList; + } } diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index 9f5e2010b3..433eccec26 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -22,9 +22,9 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; 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 static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.ArrayList; import java.util.Arrays; @@ -2346,4 +2346,110 @@ public void union() { assertEquals(Integer.valueOf(1), freq2.get(5)); } + @Test + public void testPartitionByChunkSize() { + // test with Set + final Set set = new HashSet<>(); + for (int i = 1; i <= 7; i++) { + set.add(i); + } + List> setPartitions = CollectionUtils.partitionByChunkSize(set, 3); + assertEquals(3, setPartitions.size()); + assertEquals(3, setPartitions.get(0).size()); + assertEquals(3, setPartitions.get(1).size()); + assertEquals(1, setPartitions.get(2).size()); + + // test for max chunk size use-case + List> setPartitionMaxSize = CollectionUtils.partitionByChunkSize(set, Integer.MAX_VALUE); + assertEquals(1, setPartitionMaxSize.size()); + assertEquals(set, setPartitionMaxSize.get(0)); + + // test with List, have duplicate values + final List list = new ArrayList<>(); + for (int i = 1; i <= 7; i++) { + list.add(i); + } + list.add(7L); + list.add(7L); + List> listPartitions = CollectionUtils.partitionByChunkSize(list, 2); + assertEquals(5, listPartitions.size()); + assertEquals(2, listPartitions.get(0).size()); + assertEquals(2, listPartitions.get(1).size()); + assertEquals(2, listPartitions.get(2).size()); + assertEquals(2, listPartitions.get(3).size()); + assertEquals(1, listPartitions.get(4).size()); + + // test with List, have null elements + final List listWithNullElements = new ArrayList<>(); + for (int i = 1; i <= 6; i++) { + listWithNullElements.add(i); + } + listWithNullElements.add(null); + listWithNullElements.add(7L); + List> listPartitionsWithNullElements = CollectionUtils.partitionByChunkSize(listWithNullElements, + 2); + assertEquals(4, listPartitionsWithNullElements.size()); + assertEquals(2, listPartitionsWithNullElements.get(0).size()); + assertEquals(2, listPartitionsWithNullElements.get(1).size()); + assertEquals(2, listPartitionsWithNullElements.get(2).size()); + assertEquals(2, listPartitionsWithNullElements.get(3).size()); + + // test with nested Collection + List> strLists = new ArrayList<>(); + List strList1 = Arrays.asList("1", "one"); + strLists.add(strList1); + List strList2 = Arrays.asList("2"); + strLists.add(strList2); + List strList3 = Arrays.asList("3", "three"); + strLists.add(strList3); + List strList4 = Arrays.asList("4", null); + strLists.add(strList4); + List strList5 = Arrays.asList("5", "five"); + strLists.add(strList5); + List>> retStrLists = CollectionUtils.partitionByChunkSize(strLists, 2); + assertEquals(3, retStrLists.size()); + assertEquals(2, retStrLists.get(0).size()); + assertEquals(strList1, retStrLists.get(0).get(0)); + assertEquals(strList2, retStrLists.get(0).get(1)); + assertEquals(2, retStrLists.get(1).size()); + assertEquals(strList3, retStrLists.get(1).get(0)); + assertEquals(strList4, retStrLists.get(1).get(1)); + assertEquals(1, retStrLists.get(2).size()); + assertEquals(strList5, retStrLists.get(2).get(0)); + + // test exception scenarios + try { + CollectionUtils.partitionByChunkSize(listWithNullElements, -2); + fail("failed to check if input chunk size is greater than 0"); + } catch (final IllegalArgumentException e) { + assertEquals("input chunk size must be greater than 0", e.getMessage()); + } + + try { + CollectionUtils.partitionByChunkSize(null, 2); + fail("failed to check if input collection is null"); + } catch (final NullPointerException e) { + assertEquals("input collection must not be null", e.getMessage()); + } + + try { + CollectionUtils.partitionByChunkSize(new ArrayList<>(), 2); + fail("failed to check if input collection is empty"); + } catch (final IllegalArgumentException e) { + assertEquals("input collection must not be empty", e.getMessage()); + } + + try { + @SuppressWarnings("rawtypes") + Collection mockCollection = createMock(Collection.class); + expect(mockCollection.size()).andReturn(10).anyTimes(); + expect(mockCollection.iterator()).andReturn(createMock(Iterator.class)).anyTimes(); + replay(); + CollectionUtils.partitionByChunkSize(mockCollection, 2); + fail("failed to check if input collection is empty"); + } catch (final IllegalArgumentException e) { + assertEquals("unable to get instance of given input collection", e.getMessage()); + } + } + } From e54fe11aafb514e688021bf7cee74b3904ebbb6a Mon Sep 17 00:00:00 2001 From: Ramanan Date: Mon, 29 Nov 2021 21:06:16 +0530 Subject: [PATCH 02/14] fix indentation issue --- .../java/org/apache/commons/collections4/CollectionUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index 0e0886ab61..16e95a4f72 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -2179,7 +2179,7 @@ public static E extractSingleton(final Collection collection) { * @throws IllegalArgumentException if new instance of input collection cannot * be instantiated */ - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({ "unchecked", "rawtypes" }) public static List partitionByChunkSize(final E collection, int chunkSize) { Objects.requireNonNull(collection, "input collection must not be null"); if (collection.size() == 0) { From d254abb41404f595697166dbec1e621de770e703 Mon Sep 17 00:00:00 2001 From: Ramanan Date: Mon, 29 Nov 2021 23:04:15 +0530 Subject: [PATCH 03/14] incorporate review comments --- .../apache/commons/collections4/CollectionUtils.java | 10 +++++----- .../commons/collections4/CollectionUtilsTest.java | 12 +++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index 16e95a4f72..7417e2fe04 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -2165,7 +2165,11 @@ public static E extractSingleton(final Collection collection) { * {@code collection} where the first two collections will have three elements * each and the final collection will have one element. Ordering of elements * would be based on that of the {@link Iterator} of the given - * {@code collection}. + * {@code collection}. Passing an empty collection {@code collection} as input + * would return an empty list {@link List}. Passing chunkSize {@code chunkSize} + * greater than the size of input collection {@code collection} would return a + * list {@link List} with just one element which would inturn be the input + * collection {@code collection} itself. * * @param the type of Collection * @param collection the collection to be partitioned @@ -2173,7 +2177,6 @@ public static E extractSingleton(final Collection collection) { * smaller) * @return a list of collections (type as that of given input collection) * @throws NullPointerException if the input collection is null - * @throws IllegalArgumentException if the input collection is empty * @throws IllegalArgumentException if the input chunkSize is lesser than or * equal to 0 * @throws IllegalArgumentException if new instance of input collection cannot @@ -2182,9 +2185,6 @@ public static E extractSingleton(final Collection collection) { @SuppressWarnings({ "unchecked", "rawtypes" }) public static List partitionByChunkSize(final E collection, int chunkSize) { Objects.requireNonNull(collection, "input collection must not be null"); - if (collection.size() == 0) { - throw new IllegalArgumentException("input collection must not be empty"); - } if (chunkSize <= 0) { throw new IllegalArgumentException("input chunk size must be greater than 0"); } diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index 433eccec26..d3cf4936f2 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -2417,6 +2417,11 @@ public void testPartitionByChunkSize() { assertEquals(1, retStrLists.get(2).size()); assertEquals(strList5, retStrLists.get(2).get(0)); + // test with empty collection + List emptyList = new ArrayList<>(); + List> emptyPartitions = CollectionUtils.partitionByChunkSize(emptyList, 2); + assertEquals(0, emptyPartitions.size()); + // test exception scenarios try { CollectionUtils.partitionByChunkSize(listWithNullElements, -2); @@ -2432,13 +2437,6 @@ public void testPartitionByChunkSize() { assertEquals("input collection must not be null", e.getMessage()); } - try { - CollectionUtils.partitionByChunkSize(new ArrayList<>(), 2); - fail("failed to check if input collection is empty"); - } catch (final IllegalArgumentException e) { - assertEquals("input collection must not be empty", e.getMessage()); - } - try { @SuppressWarnings("rawtypes") Collection mockCollection = createMock(Collection.class); From b347f2115b1e229e5dfd245ae6b98909d8c3f905 Mon Sep 17 00:00:00 2001 From: Ramanan Date: Wed, 1 Dec 2021 00:29:10 +0530 Subject: [PATCH 04/14] fix indentation issue --- .../commons/collections4/CollectionUtils.java | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index 7417e2fe04..3c3fad3b37 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -2156,58 +2156,58 @@ public static E extractSingleton(final Collection collection) { return collection.iterator().next(); } - /** - * Returns partitions of given collection {@code collection}, each of size - * {@code chunkSize} (the final partition may be smaller). For example, - * partitioning a collection {@code collection} containing - * {@code [a, b, c, d, e, f, g]} with a chunkSize {@code chunkSize} of 3 yields - * an outer list {@link List} containing three collections of type - * {@code collection} where the first two collections will have three elements - * each and the final collection will have one element. Ordering of elements - * would be based on that of the {@link Iterator} of the given - * {@code collection}. Passing an empty collection {@code collection} as input - * would return an empty list {@link List}. Passing chunkSize {@code chunkSize} - * greater than the size of input collection {@code collection} would return a - * list {@link List} with just one element which would inturn be the input - * collection {@code collection} itself. - * - * @param the type of Collection - * @param collection the collection to be partitioned - * @param chunkSize the desired size of each partition (the last may be - * smaller) - * @return a list of collections (type as that of given input collection) - * @throws NullPointerException if the input collection is null - * @throws IllegalArgumentException if the input chunkSize is lesser than or - * equal to 0 - * @throws IllegalArgumentException if new instance of input collection cannot - * be instantiated - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static List partitionByChunkSize(final E collection, int chunkSize) { - Objects.requireNonNull(collection, "input collection must not be null"); - if (chunkSize <= 0) { - throw new IllegalArgumentException("input chunk size must be greater than 0"); - } - List returnList = new ArrayList<>(); - Iterator iterator = collection.iterator(); - int counter = chunkSize; - try { - E tempCollection = (E) collection.getClass().newInstance(); - while (iterator.hasNext()) { - tempCollection.add(iterator.next()); - counter--; - if (counter == 0) { - returnList.add(tempCollection); - tempCollection = (E) collection.getClass().newInstance(); - counter = chunkSize; - } - } - if (tempCollection.size() > 0) { - returnList.add(tempCollection); - } - } catch (IllegalAccessException | InstantiationException e) { - throw new IllegalArgumentException("unable to get instance of given input collection"); - } - return returnList; - } + /** + * Returns partitions of given collection {@code collection}, each of size + * {@code chunkSize} (the final partition may be smaller). For example, + * partitioning a collection {@code collection} containing + * {@code [a, b, c, d, e, f, g]} with a chunkSize {@code chunkSize} of 3 yields + * an outer list {@link List} containing three collections of type + * {@code collection} where the first two collections will have three elements + * each and the final collection will have one element. Ordering of elements + * would be based on that of the {@link Iterator} of the given + * {@code collection}. Passing an empty collection {@code collection} as input + * would return an empty list {@link List}. Passing chunkSize {@code chunkSize} + * greater than the size of input collection {@code collection} would return a + * list {@link List} with just one element which would inturn be the input + * collection {@code collection} itself. + * + * @param the type of Collection + * @param collection the collection to be partitioned + * @param chunkSize the desired size of each partition (the last may be + * smaller) + * @return a list of collections (type as that of given input collection) + * @throws NullPointerException if the input collection is null + * @throws IllegalArgumentException if the input chunkSize is lesser than or + * equal to 0 + * @throws IllegalArgumentException if new instance of input collection cannot + * be instantiated + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static List partitionByChunkSize(final E collection, int chunkSize) { + Objects.requireNonNull(collection, "input collection must not be null"); + if (chunkSize <= 0) { + throw new IllegalArgumentException("input chunk size must be greater than 0"); + } + List returnList = new ArrayList<>(); + Iterator iterator = collection.iterator(); + int counter = chunkSize; + try { + E tempCollection = (E) collection.getClass().newInstance(); + while (iterator.hasNext()) { + tempCollection.add(iterator.next()); + counter--; + if (counter == 0) { + returnList.add(tempCollection); + tempCollection = (E) collection.getClass().newInstance(); + counter = chunkSize; + } + } + if (tempCollection.size() > 0) { + returnList.add(tempCollection); + } + } catch (IllegalAccessException | InstantiationException e) { + throw new IllegalArgumentException("unable to get instance of given input collection"); + } + return returnList; + } } From ffc76dba646964c8be3397faf1e3de008a6b55ec Mon Sep 17 00:00:00 2001 From: Ramanan Date: Wed, 1 Dec 2021 01:07:28 +0530 Subject: [PATCH 05/14] fix indentation issue in UTs --- .../collections4/CollectionUtilsTest.java | 206 +++++++++--------- 1 file changed, 103 insertions(+), 103 deletions(-) diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index d3cf4936f2..d800780b09 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -2346,108 +2346,108 @@ public void union() { assertEquals(Integer.valueOf(1), freq2.get(5)); } - @Test - public void testPartitionByChunkSize() { - // test with Set - final Set set = new HashSet<>(); - for (int i = 1; i <= 7; i++) { - set.add(i); - } - List> setPartitions = CollectionUtils.partitionByChunkSize(set, 3); - assertEquals(3, setPartitions.size()); - assertEquals(3, setPartitions.get(0).size()); - assertEquals(3, setPartitions.get(1).size()); - assertEquals(1, setPartitions.get(2).size()); - - // test for max chunk size use-case - List> setPartitionMaxSize = CollectionUtils.partitionByChunkSize(set, Integer.MAX_VALUE); - assertEquals(1, setPartitionMaxSize.size()); - assertEquals(set, setPartitionMaxSize.get(0)); - - // test with List, have duplicate values - final List list = new ArrayList<>(); - for (int i = 1; i <= 7; i++) { - list.add(i); - } - list.add(7L); - list.add(7L); - List> listPartitions = CollectionUtils.partitionByChunkSize(list, 2); - assertEquals(5, listPartitions.size()); - assertEquals(2, listPartitions.get(0).size()); - assertEquals(2, listPartitions.get(1).size()); - assertEquals(2, listPartitions.get(2).size()); - assertEquals(2, listPartitions.get(3).size()); - assertEquals(1, listPartitions.get(4).size()); - - // test with List, have null elements - final List listWithNullElements = new ArrayList<>(); - for (int i = 1; i <= 6; i++) { - listWithNullElements.add(i); - } - listWithNullElements.add(null); - listWithNullElements.add(7L); - List> listPartitionsWithNullElements = CollectionUtils.partitionByChunkSize(listWithNullElements, - 2); - assertEquals(4, listPartitionsWithNullElements.size()); - assertEquals(2, listPartitionsWithNullElements.get(0).size()); - assertEquals(2, listPartitionsWithNullElements.get(1).size()); - assertEquals(2, listPartitionsWithNullElements.get(2).size()); - assertEquals(2, listPartitionsWithNullElements.get(3).size()); - - // test with nested Collection - List> strLists = new ArrayList<>(); - List strList1 = Arrays.asList("1", "one"); - strLists.add(strList1); - List strList2 = Arrays.asList("2"); - strLists.add(strList2); - List strList3 = Arrays.asList("3", "three"); - strLists.add(strList3); - List strList4 = Arrays.asList("4", null); - strLists.add(strList4); - List strList5 = Arrays.asList("5", "five"); - strLists.add(strList5); - List>> retStrLists = CollectionUtils.partitionByChunkSize(strLists, 2); - assertEquals(3, retStrLists.size()); - assertEquals(2, retStrLists.get(0).size()); - assertEquals(strList1, retStrLists.get(0).get(0)); - assertEquals(strList2, retStrLists.get(0).get(1)); - assertEquals(2, retStrLists.get(1).size()); - assertEquals(strList3, retStrLists.get(1).get(0)); - assertEquals(strList4, retStrLists.get(1).get(1)); - assertEquals(1, retStrLists.get(2).size()); - assertEquals(strList5, retStrLists.get(2).get(0)); - - // test with empty collection - List emptyList = new ArrayList<>(); - List> emptyPartitions = CollectionUtils.partitionByChunkSize(emptyList, 2); - assertEquals(0, emptyPartitions.size()); - - // test exception scenarios - try { - CollectionUtils.partitionByChunkSize(listWithNullElements, -2); - fail("failed to check if input chunk size is greater than 0"); - } catch (final IllegalArgumentException e) { - assertEquals("input chunk size must be greater than 0", e.getMessage()); - } - - try { - CollectionUtils.partitionByChunkSize(null, 2); - fail("failed to check if input collection is null"); - } catch (final NullPointerException e) { - assertEquals("input collection must not be null", e.getMessage()); - } - - try { - @SuppressWarnings("rawtypes") - Collection mockCollection = createMock(Collection.class); - expect(mockCollection.size()).andReturn(10).anyTimes(); - expect(mockCollection.iterator()).andReturn(createMock(Iterator.class)).anyTimes(); - replay(); - CollectionUtils.partitionByChunkSize(mockCollection, 2); - fail("failed to check if input collection is empty"); - } catch (final IllegalArgumentException e) { - assertEquals("unable to get instance of given input collection", e.getMessage()); - } - } + @Test + public void testPartitionByChunkSize() { + // test with Set + final Set set = new HashSet<>(); + for (int i = 1; i <= 7; i++) { + set.add(i); + } + List> setPartitions = CollectionUtils.partitionByChunkSize(set, 3); + assertEquals(3, setPartitions.size()); + assertEquals(3, setPartitions.get(0).size()); + assertEquals(3, setPartitions.get(1).size()); + assertEquals(1, setPartitions.get(2).size()); + + // test for max chunk size use-case + List> setPartitionMaxSize = CollectionUtils.partitionByChunkSize(set, Integer.MAX_VALUE); + assertEquals(1, setPartitionMaxSize.size()); + assertEquals(set, setPartitionMaxSize.get(0)); + + // test with List, have duplicate values + final List list = new ArrayList<>(); + for (int i = 1; i <= 7; i++) { + list.add(i); + } + list.add(7L); + list.add(7L); + List> listPartitions = CollectionUtils.partitionByChunkSize(list, 2); + assertEquals(5, listPartitions.size()); + assertEquals(2, listPartitions.get(0).size()); + assertEquals(2, listPartitions.get(1).size()); + assertEquals(2, listPartitions.get(2).size()); + assertEquals(2, listPartitions.get(3).size()); + assertEquals(1, listPartitions.get(4).size()); + + // test with List, have null elements + final List listWithNullElements = new ArrayList<>(); + for (int i = 1; i <= 6; i++) { + listWithNullElements.add(i); + } + listWithNullElements.add(null); + listWithNullElements.add(7L); + List> listPartitionsWithNullElements = CollectionUtils.partitionByChunkSize(listWithNullElements, + 2); + assertEquals(4, listPartitionsWithNullElements.size()); + assertEquals(2, listPartitionsWithNullElements.get(0).size()); + assertEquals(2, listPartitionsWithNullElements.get(1).size()); + assertEquals(2, listPartitionsWithNullElements.get(2).size()); + assertEquals(2, listPartitionsWithNullElements.get(3).size()); + + // test with nested Collection + List> strLists = new ArrayList<>(); + List strList1 = Arrays.asList("1", "one"); + strLists.add(strList1); + List strList2 = Arrays.asList("2"); + strLists.add(strList2); + List strList3 = Arrays.asList("3", "three"); + strLists.add(strList3); + List strList4 = Arrays.asList("4", null); + strLists.add(strList4); + List strList5 = Arrays.asList("5", "five"); + strLists.add(strList5); + List>> retStrLists = CollectionUtils.partitionByChunkSize(strLists, 2); + assertEquals(3, retStrLists.size()); + assertEquals(2, retStrLists.get(0).size()); + assertEquals(strList1, retStrLists.get(0).get(0)); + assertEquals(strList2, retStrLists.get(0).get(1)); + assertEquals(2, retStrLists.get(1).size()); + assertEquals(strList3, retStrLists.get(1).get(0)); + assertEquals(strList4, retStrLists.get(1).get(1)); + assertEquals(1, retStrLists.get(2).size()); + assertEquals(strList5, retStrLists.get(2).get(0)); + + // test with empty collection + List emptyList = new ArrayList<>(); + List> emptyPartitions = CollectionUtils.partitionByChunkSize(emptyList, 2); + assertEquals(0, emptyPartitions.size()); + + // test exception scenarios + try { + CollectionUtils.partitionByChunkSize(listWithNullElements, -2); + fail("failed to check if input chunk size is greater than 0"); + } catch (final IllegalArgumentException e) { + assertEquals("input chunk size must be greater than 0", e.getMessage()); + } + + try { + CollectionUtils.partitionByChunkSize(null, 2); + fail("failed to check if input collection is null"); + } catch (final NullPointerException e) { + assertEquals("input collection must not be null", e.getMessage()); + } + + try { + @SuppressWarnings("rawtypes") + Collection mockCollection = createMock(Collection.class); + expect(mockCollection.size()).andReturn(10).anyTimes(); + expect(mockCollection.iterator()).andReturn(createMock(Iterator.class)).anyTimes(); + replay(); + CollectionUtils.partitionByChunkSize(mockCollection, 2); + fail("failed to check if input collection is empty"); + } catch (final IllegalArgumentException e) { + assertEquals("unable to get instance of given input collection", e.getMessage()); + } + } } From b9284b8cb16b0aaac730618a5dcac80b80d75352 Mon Sep 17 00:00:00 2001 From: Ramanan Date: Thu, 2 Dec 2021 21:52:42 +0530 Subject: [PATCH 06/14] incorporate review comments --- .../commons/collections4/CollectionUtils.java | 37 ++++++++----------- .../collections4/CollectionUtilsTest.java | 10 ++++- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index 3c3fad3b37..5f7cf5f92b 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -30,6 +30,9 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import java.util.stream.Collectors; import org.apache.commons.collections4.bag.HashBag; import org.apache.commons.collections4.collection.PredicatedCollection; @@ -2168,7 +2171,7 @@ public static E extractSingleton(final Collection collection) { * {@code collection}. Passing an empty collection {@code collection} as input * would return an empty list {@link List}. Passing chunkSize {@code chunkSize} * greater than the size of input collection {@code collection} would return a - * list {@link List} with just one element which would inturn be the input + * list {@link List} with just one element which would in-turn be the input * collection {@code collection} itself. * * @param the type of Collection @@ -2183,31 +2186,21 @@ public static E extractSingleton(final Collection collection) { * be instantiated */ @SuppressWarnings({ "unchecked", "rawtypes" }) - public static List partitionByChunkSize(final E collection, int chunkSize) { + public static List partitionByChunkSize(final T collection, int chunkSize) { Objects.requireNonNull(collection, "input collection must not be null"); if (chunkSize <= 0) { throw new IllegalArgumentException("input chunk size must be greater than 0"); } - List returnList = new ArrayList<>(); - Iterator iterator = collection.iterator(); - int counter = chunkSize; - try { - E tempCollection = (E) collection.getClass().newInstance(); - while (iterator.hasNext()) { - tempCollection.add(iterator.next()); - counter--; - if (counter == 0) { - returnList.add(tempCollection); - tempCollection = (E) collection.getClass().newInstance(); - counter = chunkSize; - } - } - if (tempCollection.size() > 0) { - returnList.add(tempCollection); + Supplier supplier = () -> { + try { + return (T) collection.getClass().newInstance(); + } catch (IllegalAccessException | InstantiationException e) { + throw new IllegalArgumentException("unable to get instance of given input collection"); } - } catch (IllegalAccessException | InstantiationException e) { - throw new IllegalArgumentException("unable to get instance of given input collection"); - } - return returnList; + }; + final AtomicInteger counter = new AtomicInteger(0); + final Map map = (Map) collection.stream().collect( + Collectors.groupingBy((i -> counter.getAndIncrement() / chunkSize), Collectors.toCollection(supplier))); + return new ArrayList<>(map.values()); } } diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index d800780b09..c09c846156 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -2429,6 +2429,13 @@ public void testPartitionByChunkSize() { } catch (final IllegalArgumentException e) { assertEquals("input chunk size must be greater than 0", e.getMessage()); } + + try { + CollectionUtils.partitionByChunkSize(listWithNullElements, 0); + fail("failed to check if input chunk size is greater than 0"); + } catch (final IllegalArgumentException e) { + assertEquals("input chunk size must be greater than 0", e.getMessage()); + } try { CollectionUtils.partitionByChunkSize(null, 2); @@ -2440,8 +2447,7 @@ public void testPartitionByChunkSize() { try { @SuppressWarnings("rawtypes") Collection mockCollection = createMock(Collection.class); - expect(mockCollection.size()).andReturn(10).anyTimes(); - expect(mockCollection.iterator()).andReturn(createMock(Iterator.class)).anyTimes(); + expect(mockCollection.stream()).andReturn(Arrays.asList("").stream()); replay(); CollectionUtils.partitionByChunkSize(mockCollection, 2); fail("failed to check if input collection is empty"); From d6ef0557568d56616ae6af6bc8944c613f0be308 Mon Sep 17 00:00:00 2001 From: Ramanan Date: Thu, 2 Dec 2021 22:12:27 +0530 Subject: [PATCH 07/14] incorporate review comments --- .../apache/commons/collections4/CollectionUtils.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index 5f7cf5f92b..252203e43b 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -2167,7 +2167,7 @@ public static E extractSingleton(final Collection collection) { * an outer list {@link List} containing three collections of type * {@code collection} where the first two collections will have three elements * each and the final collection will have one element. Ordering of elements - * would be based on that of the {@link Iterator} of the given + * would be based on that of the {@link Stream} of the given * {@code collection}. Passing an empty collection {@code collection} as input * would return an empty list {@link List}. Passing chunkSize {@code chunkSize} * greater than the size of input collection {@code collection} would return a @@ -2186,20 +2186,20 @@ public static E extractSingleton(final Collection collection) { * be instantiated */ @SuppressWarnings({ "unchecked", "rawtypes" }) - public static List partitionByChunkSize(final T collection, int chunkSize) { + public static List partitionByChunkSize(final E collection, int chunkSize) { Objects.requireNonNull(collection, "input collection must not be null"); if (chunkSize <= 0) { throw new IllegalArgumentException("input chunk size must be greater than 0"); } - Supplier supplier = () -> { + Supplier supplier = () -> { try { - return (T) collection.getClass().newInstance(); + return (E) collection.getClass().newInstance(); } catch (IllegalAccessException | InstantiationException e) { throw new IllegalArgumentException("unable to get instance of given input collection"); } }; final AtomicInteger counter = new AtomicInteger(0); - final Map map = (Map) collection.stream().collect( + final Map map = (Map) collection.stream().collect( Collectors.groupingBy((i -> counter.getAndIncrement() / chunkSize), Collectors.toCollection(supplier))); return new ArrayList<>(map.values()); } From 6bb5294ddc16063ec655e83508fd4df3b60b2879 Mon Sep 17 00:00:00 2001 From: Ramanan Date: Fri, 3 Dec 2021 00:45:47 +0530 Subject: [PATCH 08/14] fix indentation issue --- .../org/apache/commons/collections4/CollectionUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index c09c846156..d1c29de913 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -2429,7 +2429,7 @@ public void testPartitionByChunkSize() { } catch (final IllegalArgumentException e) { assertEquals("input chunk size must be greater than 0", e.getMessage()); } - + try { CollectionUtils.partitionByChunkSize(listWithNullElements, 0); fail("failed to check if input chunk size is greater than 0"); From c35425d6f02e1fbc9c1d75b82b74d8d2f13c65bd Mon Sep 17 00:00:00 2001 From: Ramanan Date: Fri, 3 Dec 2021 12:39:17 +0530 Subject: [PATCH 09/14] fix javadocs --- .../commons/collections4/CollectionUtils.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index 252203e43b..0530a76098 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -2160,19 +2160,22 @@ public static E extractSingleton(final Collection collection) { } /** - * Returns partitions of given collection {@code collection}, each of size - * {@code chunkSize} (the final partition may be smaller). For example, - * partitioning a collection {@code collection} containing - * {@code [a, b, c, d, e, f, g]} with a chunkSize {@code chunkSize} of 3 yields - * an outer list {@link List} containing three collections of type - * {@code collection} where the first two collections will have three elements - * each and the final collection will have one element. Ordering of elements - * would be based on that of the {@link Stream} of the given - * {@code collection}. Passing an empty collection {@code collection} as input - * would return an empty list {@link List}. Passing chunkSize {@code chunkSize} - * greater than the size of input collection {@code collection} would return a - * list {@link List} with just one element which would in-turn be the input - * collection {@code collection} itself. + * Returns partitions of given {@code collection}, each of size + * {@code chunkSize} (the final partition may be smaller). + *

+ * For example, partitioning a {@code collection} containing + * {@code [a, b, c, d, e, f, g]} with a {@code chunkSize} of 3 yields an outer + * {@link List} containing three collections of type {@code collection} where + * the first two collections will have three elements each and the final + * collection will have one element. Ordering of elements would be based on that + * of the Stream of the given {@code collection}. + *

+ *

+ * Passing an empty {@code collection} as input would return an empty + * {@link List}. Passing {@code chunkSize} greater than the size of input + * {@code collection} would return a {@link List} with just one element which + * would in-turn be the input {@code collection} itself. + *

* * @param the type of Collection * @param collection the collection to be partitioned From b142dc4285156b4537772b4c67b86a782f4f38e8 Mon Sep 17 00:00:00 2001 From: Ramanan Date: Fri, 17 Dec 2021 22:45:32 +0530 Subject: [PATCH 10/14] replace usage of deprecated newInstance --- .../org/apache/commons/collections4/CollectionUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index 0530a76098..954ee2162a 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -17,6 +17,7 @@ package org.apache.commons.collections4; import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -2196,8 +2197,9 @@ public static List partitionByChunkSize(final E collec } Supplier supplier = () -> { try { - return (E) collection.getClass().newInstance(); - } catch (IllegalAccessException | InstantiationException e) { + return (E) collection.getClass().getDeclaredConstructor().newInstance(); + } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException + | InstantiationException e) { throw new IllegalArgumentException("unable to get instance of given input collection"); } }; From c6a4970b265147b42ebc694efd254cd32759d080 Mon Sep 17 00:00:00 2001 From: ramananravi <91211479+ramananravi@users.noreply.github.com> Date: Wed, 5 Apr 2023 15:46:58 +0530 Subject: [PATCH 11/14] fix tests with assertThrows --- .../collections4/CollectionUtilsTest.java | 55 ++++++++----------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index ab2b121468..253aa8ef6f 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -25,7 +25,6 @@ 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 static org.junit.jupiter.api.Assertions.fail; import java.util.ArrayList; import java.util.Arrays; @@ -2379,39 +2378,29 @@ public void testPartitionByChunkSize() { List emptyList = new ArrayList<>(); List> emptyPartitions = CollectionUtils.partitionByChunkSize(emptyList, 2); assertEquals(0, emptyPartitions.size()); - // test exception scenarios - try { - CollectionUtils.partitionByChunkSize(listWithNullElements, -2); - fail("failed to check if input chunk size is greater than 0"); - } catch (final IllegalArgumentException e) { - assertEquals("input chunk size must be greater than 0", e.getMessage()); - } - - try { - CollectionUtils.partitionByChunkSize(listWithNullElements, 0); - fail("failed to check if input chunk size is greater than 0"); - } catch (final IllegalArgumentException e) { - assertEquals("input chunk size must be greater than 0", e.getMessage()); - } - - try { - CollectionUtils.partitionByChunkSize(null, 2); - fail("failed to check if input collection is null"); - } catch (final NullPointerException e) { - assertEquals("input collection must not be null", e.getMessage()); - } - - try { - @SuppressWarnings("rawtypes") - Collection mockCollection = createMock(Collection.class); - expect(mockCollection.stream()).andReturn(Arrays.asList("").stream()); - replay(); - CollectionUtils.partitionByChunkSize(mockCollection, 2); - fail("failed to check if input collection is empty"); - } catch (final IllegalArgumentException e) { - assertEquals("unable to get instance of given input collection", e.getMessage()); - } + assertAll( + () -> { + assertThrows(IllegalArgumentException.class, () -> CollectionUtils.partitionByChunkSize(listWithNullElements, -2), + "failed to check if input chunk size is greater than 0"); + }, + () -> { + assertThrows(IllegalArgumentException.class, () -> CollectionUtils.partitionByChunkSize(listWithNullElements, 0), + "failed to check if input chunk size is greater than 0"); + }, + () -> { + assertThrows(NullPointerException.class, () -> CollectionUtils.partitionByChunkSize(null, 2), + "failed to check if input collection is null"); + }, + () -> { + @SuppressWarnings("rawtypes") + Collection mockCollection = createMock(Collection.class); + expect(mockCollection.stream()).andReturn(Arrays.asList("").stream()); + replay(); + assertThrows(IllegalArgumentException.class, () -> CollectionUtils.partitionByChunkSize(mockCollection, 2), + "failed to check if input collection is empty"); + } + ); } } From 73fafecb9f1f05de14be43f080bca24122e9ec33 Mon Sep 17 00:00:00 2001 From: ramananravi <91211479+ramananravi@users.noreply.github.com> Date: Wed, 5 Apr 2023 16:01:13 +0530 Subject: [PATCH 12/14] fix indentation --- .../org/apache/commons/collections4/CollectionUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index 253aa8ef6f..6a554ed6c7 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -2393,7 +2393,7 @@ public void testPartitionByChunkSize() { "failed to check if input collection is null"); }, () -> { - @SuppressWarnings("rawtypes") + @SuppressWarnings("rawtypes") Collection mockCollection = createMock(Collection.class); expect(mockCollection.stream()).andReturn(Arrays.asList("").stream()); replay(); From 70a2e5d5f9d5b34c46189d5aeb000d7375c62fc7 Mon Sep 17 00:00:00 2001 From: ramananravi <91211479+ramananravi@users.noreply.github.com> Date: Wed, 5 Apr 2023 16:02:14 +0530 Subject: [PATCH 13/14] fix indentation --- .../org/apache/commons/collections4/CollectionUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index 6a554ed6c7..4841d024b5 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -2393,7 +2393,7 @@ public void testPartitionByChunkSize() { "failed to check if input collection is null"); }, () -> { - @SuppressWarnings("rawtypes") + @SuppressWarnings("rawtypes") Collection mockCollection = createMock(Collection.class); expect(mockCollection.stream()).andReturn(Arrays.asList("").stream()); replay(); From 3d9520975fd8c1fdf1f28cc8719d6797e6f37c68 Mon Sep 17 00:00:00 2001 From: ramananravi <91211479+ramananravi@users.noreply.github.com> Date: Wed, 5 Apr 2023 16:09:23 +0530 Subject: [PATCH 14/14] fix assertion message --- .../org/apache/commons/collections4/CollectionUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index 4841d024b5..97d623e23c 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -2398,7 +2398,7 @@ public void testPartitionByChunkSize() { expect(mockCollection.stream()).andReturn(Arrays.asList("").stream()); replay(); assertThrows(IllegalArgumentException.class, () -> CollectionUtils.partitionByChunkSize(mockCollection, 2), - "failed to check if input collection is empty"); + "failed to check instance of given input collection"); } ); }