Skip to content

Commit 5f892b3

Browse files
author
zihluwang
committed
feat: chunk list with specified list type
1 parent 1a29a4c commit 5f892b3

File tree

2 files changed

+156
-12
lines changed

2 files changed

+156
-12
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (C) 2024-2025 OnixByte.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
*
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package com.onixbyte.devkit.utils;
19+
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
import java.util.ArrayList;
24+
import java.util.Collection;
25+
import java.util.List;
26+
import java.util.Objects;
27+
import java.util.function.Supplier;
28+
29+
/**
30+
* A utility class providing static methods for manipulating collections.
31+
*
32+
* @author zihluwang
33+
*/
34+
public final class CollectionUtil {
35+
36+
private static final Logger log = LoggerFactory.getLogger(CollectionUtil.class);
37+
38+
/**
39+
* Private constructor to prevent instantiation of this utility class.
40+
*/
41+
private CollectionUtil() {
42+
}
43+
44+
/**
45+
* Splits a collection into a list of sub-collections, each with a maximum size specified by
46+
* the caller.
47+
* <p>
48+
* This method takes an original collection and divides it into smaller sub-collections,
49+
* ensuring that each sub-collection contains no more than the specified maximum size. If the
50+
* original collection's size is less than or equal to the maximum size, it is returned as a
51+
* single sub-collection. The sub-collections are created using the provided collection factory.
52+
*
53+
* @param <T> the type of elements in the collection
54+
* @param <C> the type of the collection, which must extend {@link Collection}
55+
* @param originalCollection the collection to be split into sub-collections
56+
* @param maxSize the maximum number of elements allowed in each sub-collection
57+
* @param collectionFactory a supplier that creates new instances of the sub-collection type
58+
* @return a list of sub-collections, each containing up to {@code maxSize} elements
59+
* @throws IllegalArgumentException if {@code originalCollection} is {@code null},
60+
* {@code maxSize} is less than zero, or
61+
* {@code collectionFactory} is {@code null}
62+
*/
63+
public static <T, C extends Collection<T>> List<C> chunk(C originalCollection,
64+
int maxSize,
65+
Supplier<C> collectionFactory) {
66+
// check inputs
67+
if (Objects.isNull(originalCollection)) {
68+
throw new IllegalArgumentException("Collection must not be null.");
69+
}
70+
71+
if (maxSize < 0) {
72+
throw new IllegalArgumentException("maxSize must greater than 0.");
73+
}
74+
75+
if (Objects.isNull(collectionFactory)) {
76+
throw new IllegalArgumentException("Factory method cannot be null.");
77+
}
78+
79+
var result = new ArrayList<C>();
80+
var size = originalCollection.size();
81+
82+
// if original collection is empty or the size less than maxSize, return it as a single
83+
// sub collection
84+
if (size <= maxSize) {
85+
var singleCollection = collectionFactory.get();
86+
singleCollection.addAll(originalCollection);
87+
result.add(singleCollection);
88+
return result;
89+
}
90+
91+
// use iterator to split the given collection
92+
var iter = originalCollection.iterator();
93+
var count = 0;
94+
var currentSubCollection = collectionFactory.get();
95+
96+
while (iter.hasNext()) {
97+
var element = iter.next();
98+
currentSubCollection.add(element);
99+
count++;
100+
101+
// add sub collection to result when current sub collection reached maxSize or
102+
// collection traverse is completed
103+
if (count % maxSize == 0 || !iter.hasNext()) {
104+
result.add(currentSubCollection);
105+
currentSubCollection = collectionFactory.get();
106+
}
107+
}
108+
109+
return result;
110+
}
111+
112+
}

devkit-utils/src/main/java/com/onixbyte/devkit/utils/ListUtil.java

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,19 @@
1919

2020
import java.util.ArrayList;
2121
import java.util.List;
22+
import java.util.Objects;
23+
import java.util.function.Supplier;
2224

2325
/**
24-
* A utility class for splitting a List into multiple sub lists, where each sublist has a maximum
25-
* number of elements specified by the user.
26+
* A utility class providing static methods for manipulating lists.
2627
*
2728
* @author siujamo
29+
* @author zihluwang
2830
*/
2931
public final class ListUtil {
3032

3133
/**
3234
* Private constructor to prevent instantiation of this utility class.
33-
* <p>
34-
* This class provides static methods for list manipulation and is not intended to be
35-
* instantiated. The private constructor ensures that no instances can be created, enforcing
36-
* the utility nature of the class.
3735
*/
3836
private ListUtil() {
3937
}
@@ -50,33 +48,67 @@ private ListUtil() {
5048
* @param <T> the type of elements in the list
5149
* @param originalList the list to be split, must not be null
5250
* @param maxSize the maximum number of elements in each sublist, must be positive
51+
* @param listFactory list factory
5352
* @return a List of sub lists, where each sublist has at most {@code maxSize} elements
5453
* @throws IllegalArgumentException if {@code originalList} is null or {@code maxSize} is less
5554
* than or equal to 0
5655
*/
57-
public static <T> List<List<T>> splitList(List<T> originalList, int maxSize) {
56+
public static <T> List<List<T>> chunk(List<T> originalList, int maxSize, Supplier<List<T>> listFactory) {
5857
// check input
59-
if (originalList == null || maxSize <= 0) {
60-
throw new IllegalArgumentException("List cannot be null and maxSize must be positive");
58+
if (Objects.isNull(originalList)) {
59+
throw new IllegalArgumentException("List cannot be null");
60+
}
61+
62+
if (maxSize <= 0) {
63+
throw new IllegalArgumentException("Max size should be greater than 0");
64+
}
65+
66+
if (Objects.isNull(listFactory)) {
67+
throw new IllegalArgumentException("List factory cannot be null");
6168
}
6269

6370
var result = new ArrayList<List<T>>();
6471
var size = originalList.size();
6572

6673
// if the original list is empty or smaller than maxSize, return it as a single sublist
6774
if (size <= maxSize) {
68-
result.add(new ArrayList<>(originalList));
75+
var singleSubList = listFactory.get();
76+
singleSubList.addAll(originalList);
77+
result.add(singleSubList);
6978
return result;
7079
}
7180

7281
// split the list
7382
for (var i = 0; i < size; i += maxSize) {
7483
var end = Math.min(i + maxSize, size); // ensure not to exceed list length
75-
List<T> subList = originalList.subList(i, end);
76-
result.add(new ArrayList<>(subList)); // create a new list to avoid reference issues
84+
var subList = originalList.subList(i, end);
85+
var subListWrapper = listFactory.get();
86+
subListWrapper.addAll(subList);
87+
result.add(subListWrapper); // create a new list to avoid reference issues
7788
}
7889

7990
return result;
8091
}
8192

93+
/**
94+
* Splits a given List into a List of sub lists, where each sublist contains at most
95+
* {@code maxSize} elements. The original list is not modified, and new sub lists are created
96+
* to hold the partitioned data.
97+
* <p>
98+
* If the original list's size is less than or equal to {@code maxSize}, a single sublist
99+
* containing all elements is returned. If the list is empty, an empty list of sub lists
100+
* is returned.
101+
*
102+
* @param <T> the type of elements in the list
103+
* @param originalList the list to be split, must not be null
104+
* @param maxSize the maximum number of elements in each sublist, must be positive
105+
* @return a List of sub lists, where each sublist has at most {@code maxSize} elements
106+
* @throws IllegalArgumentException if {@code originalList} is null or {@code maxSize} is less
107+
* than or equal to 0
108+
* @see #chunk(List, int, Supplier)
109+
*/
110+
public static <T> List<List<T>> chunk(List<T> originalList, int maxSize) {
111+
return chunk(originalList, maxSize, ArrayList::new);
112+
}
113+
82114
}

0 commit comments

Comments
 (0)