I have this list (List
):
[\"a\", \"b\", null, \"c\", null, \"d\", \"e\"]
And I\'d like something like this:
The solution is to use Stream.collect
. To create a Collector using its builder pattern is already given as solution. The alternative is the other overloaded collect
being a tiny bit more primitive.
List strings = Arrays.asList("a", "b", null, "c", null, "d", "e");
List> groups = strings.stream()
.collect(() -> {
List> list = new ArrayList<>();
list.add(new ArrayList<>());
return list;
},
(list, s) -> {
if (s == null) {
list.add(new ArrayList<>());
} else {
list.get(list.size() - 1).add(s);
}
},
(list1, list2) -> {
// Simple merging of partial sublists would
// introduce a false level-break at the beginning.
list1.get(list1.size() - 1).addAll(list2.remove(0));
list1.addAll(list2);
});
As one sees, I make a list of string lists, where there always is at least one last (empty) string list.
A solution with an accumulator:
As @StuartMarks points out, the combiner does not fullfill the contract for parallelism.
Due to the comment of @ArnaudDenoyelle a version using reduce
.
List> groups = strings.stream()
.reduce(new ArrayList>(),
(list, s) -> {
if (list.isEmpty()) {
list.add(new ArrayList<>());
}
if (s == null) {
list.add(new ArrayList<>());
} else {
list.get(list.size() - 1).add(s);
}
return list;
},
(list1, list2) -> {
list1.addAll(list2);
return list1;
});