Split a List into sub-lists of size `n` in Java
This post will discuss how to split a list into sub-lists of size n in Java. Note that the final list may be smaller than n depending upon the size of the list.
1. Using Guava
With the Guava library, you can use the Lists.partition() method to partition a list into consecutive sublists, each of the specified size. Following is a simple example demonstrating the usage of this method:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import com.google.common.collect.Lists; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partition = Lists.partition(collection, partitionSize); System.out.println(partition); } } |
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
2. Using Apache Commons Collections
Similar to the Guava’s Lists.partition() method, Apache Commons Collections ListUtils class offers partition() method offering the similar functionality.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import org.apache.commons.collections4.ListUtils; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partitions = ListUtils.partition(collection, partitionSize); System.out.println(partitions); } } |
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
3. Using List.subList() method
If you don’t prefer third-party libraries, you can write your own routine for this task. The following solutions use a regular for-loop to iterate the list and the List.subList() method to get the partition between starting and ending index.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partitions = new ArrayList<>(); for (int i = 0; i < collection.size(); i += partitionSize) { partitions.add(collection.subList(i, Math.min(i + partitionSize, collection.size()))); } System.out.println(partitions); } } |
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
This is equivalent to the following using Java 8 Stream API:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { private static <T> List<List<T>> partition(List<T> collection, int partitionSize) { return IntStream.rangeClosed(0, (collection.size() - 1) / partitionSize) .mapToObj(i -> collection.subList(i * partitionSize, Math.min((i + 1) * partitionSize, collection.size()))) .collect(Collectors.toList()); } public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partitions = partition(collection, partitionSize); System.out.println(partitions); } } |
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
Finally, with Java 9 you can simplify the code using the IntStream.iterate() method which takes a predicate.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { private static <T> List<List<T>> partition(List<T> collection, int partitionSize) { return IntStream.iterate(0, i -> i < collection.size(), i -> i + partitionSize) .mapToObj(i -> collection.subList(i, Math.min(i + partitionSize, collection.size()))) .collect(Collectors.toList()); } public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partitions = partition(collection, partitionSize); System.out.println(partitions); } } |
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
4. Using Collectors.groupingBy() method
There are more ways to split a list in Java using Stream API. The following solution uses Collectors.groupingBy() to perform the equivalent of a “group by” operation on the list elements. It groups the elements according to a classification function and returns the results in a map.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.util.Collection; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { private static <T> Collection<List<T>> partition(List<T> collection, int n) { return IntStream.range(0, collection.size()).boxed() .collect(Collectors.groupingBy(i -> i / n, Collectors.mapping(collection::get, Collectors.toList()))) .values(); } public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; Collection<List<Integer>> partitions = partition(collection, partitionSize); System.out.println(partitions); } } |
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
The code can be simplified using a mutable counter like AtomicInteger class:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { private static <T> Collection<List<T>> partition(List<T> collection, int n) { AtomicInteger counter = new AtomicInteger(); return collection.stream() .collect(Collectors.groupingBy(it -> counter.getAndIncrement() / n)) .values(); } public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; Collection<List<Integer>> partitions = partition(collection, partitionSize); System.out.println(partitions); } } |
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
That’s all about splitting a list into sub-lists of size n in Java.
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)