1. Overview
In this article, weβll illustrate how to split a List into several sublists of a given size.
For a relatively simple operation, thereβs surprisingly no support in the standard Java collection APIs. Luckily, both Guava and the Apache Commons Collections have implemented the operation in a similar way.
This article is part of the βJava β Back to Basicβ series here on Baeldung.
Further reading:
Converting a List to String in Java
Introduction to Spliterator in Java
2. Use Guava to Partition the List
Guava facilitates partitioning the List into sublists of a specified size via the Lists.partition operation:
@Test
public void givenList_whenParitioningIntoNSublists_thenCorrect() {
List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
List<List<Integer>> subSets = Lists.partition(intList, 3);
List<Integer> lastPartition = subSets.get(2);
List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
assertThat(subSets.size(), equalTo(3));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
3. Use Guava to Partition a Collection
Partitioning a Collection is also possible with Guava:
@Test
public void givenCollection_whenParitioningIntoNSublists_thenCorrect() {
Collection<Integer> intCollection = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Iterable<List<Integer>> subSets = Iterables.partition(intCollection, 3);
List<Integer> firstPartition = subSets.iterator().next();
List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(1, 2, 3);
assertThat(firstPartition, equalTo(expectedLastPartition));
}
Keep in mind that the partitions are sublist views of the original collection, which means that changes in the original collection will be reflected in the partitions:
@Test
public void givenListPartitioned_whenOriginalListIsModified_thenPartitionsChangeAsWell() {
// Given
List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
List<List<Integer>> subSets = Lists.partition(intList, 3);
// When
intList.add(9);
// Then
List<Integer> lastPartition = subSets.get(2);
List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8, 9);
assertThat(lastPartition, equalTo(expectedLastPartition));
}
4. Use Apache Commons Collections to Partition the List
The latest releases of Apache Commons Collections have recently added support for partitioning a List as well:
@Test
public void givenList_whenParitioningIntoNSublists_thenCorrect() {
List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
List<List<Integer>> subSets = ListUtils.partition(intList, 3);
List<Integer> lastPartition = subSets.get(2);
List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
assertThat(subSets.size(), equalTo(3));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
Commons Collections doesnβt have a corresponding option to partition a raw Collection similar to the Guava Iterables.partition.
Finally, the same caveat applies here as well: the resulting partitions are views of the original List.
5. Use Java8 to Partition the List
Now letβs see how to use Java8 to partition our List.
5.1. Collectors partitioningBy
We can use Collectors.partitioningBy() to split the list into 2 sublists:
@Test
public void givenList_whenParitioningIntoSublistsUsingPartitionBy_thenCorrect() {
List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Map<Boolean, List<Integer>> groups =
intList.stream().collect(Collectors.partitioningBy(s -> s > 6));
List<List<Integer>> subSets = new ArrayList<List<Integer>>(groups.values());
List<Integer> lastPartition = subSets.get(1);
List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
assertThat(subSets.size(), equalTo(2));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
Note: The resulting partitions arenβt a view of the main List, so any changes happening to the main List wonβt affect the partitions.
5.2. Collectors groupingBy
We can also use Collectors.groupingBy() to split our list into multiple partitions:
@Test
public final void givenList_whenParitioningIntoNSublistsUsingGroupingBy_thenCorrect() {
List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Map<Integer, List<Integer>> groups =
intList.stream().collect(Collectors.groupingBy(s -> (s - 1) / 3));
List<List<Integer>> subSets = new ArrayList<List<Integer>>(groups.values());
List<Integer> lastPartition = subSets.get(2);
List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
assertThat(subSets.size(), equalTo(3));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
Note: Just as with Collectors.partitioningBy(), the resulting partitions wonβt be affected by changes in the main List.
5.3. Split the List by Separator
We can also use Java8 to split our List by separator:
@Test
public void givenList_whenSplittingBySeparator_thenCorrect() {
List<Integer> intList = Lists.newArrayList(1, 2, 3, 0, 4, 5, 6, 0, 7, 8);
int[] indexes =
Stream.of(IntStream.of(-1), IntStream.range(0, intList.size())
.filter(i -> intList.get(i) == 0), IntStream.of(intList.size()))
.flatMapToInt(s -> s).toArray();
List<List<Integer>> subSets =
IntStream.range(0, indexes.length - 1)
.mapToObj(i -> intList.subList(indexes[i] + 1, indexes[i + 1]))
.collect(Collectors.toList());
List<Integer> lastPartition = subSets.get(2);
List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
assertThat(subSets.size(), equalTo(3));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
Note: We used β0β as separator. We first obtained the indices of all β0β elements in the List, and then we split the List on these indices.
6. Conclusion
The solutions presented here make use of additional libraries, namely Guava and the Apache Commons Collections. Both of these are very lightweight and extremely useful overall, so it makes perfect sense to have one of them on the classpath. However, if thatβs not an option, a Java only solution is shown here.
