1. overview
In this tutorial, I'll show you how to split a List into multiple sublists of a given size.
For relatively simple operations, surprisingly, there is no support in the standard Java collection API. Fortunately, Guava and Apache Commons Collections The operations are implemented in a similar way.
2. Partitioning List s with Guava
Guava facilitates splitting lists into sublists of specified sizes - via 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. Partitioning Collection s with Guava
Guava can also partition Collection s:
@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 partitions are sublist views of the original collection - this means that changes in the original collection will be reflected in the partition
@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. Partitioning List s with Apache Commons Collections
Latest version of Apache Commons Collections More recently Partitioning support for List:
@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)); }
Is there an option to divide an original collection - similar to Guava Iterables.partition in a general collection?
Finally, the same warning applies to this - the result partition is the view of the original List.
5. Partitioning List s with Java 8
Now let's see how Java 8 can be used to partition lists.
5.1. Collectors partitioningBy
We can use Collectors.partitioningBy () to split the list into two sublists - as follows:
@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 generated partition is not a view of the main List, so any changes to the main List will not affect the partition.
5.2. Collectors groupingBy
We can also use Collectors.groupingBy () to split the 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 like Collectors.partitioningBy () - the generated partitions are not affected by changes in the main List.
5.3. Split lists by separators
We can also use Java 8 to split lists 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 use "0" as the delimiter - we first get the index of all "0" elements in the List, and then we split the List on those indexes.
Six, conclusion
The solution described here uses additional libraries -- Guava or Apache Commons Collections libraries. Both are very lightweight and generally very useful, so it makes sense to use one of them in the classpath; however, if this is not an option- Here only display A Java solution.
All of these examples and code snippets can be implemented Find it on GitHub - This is a Maven-based project, so it should be easy to import and run.