Splitting List into sublists along elements

后端 未结 13 1887
野趣味
野趣味 2020-11-28 21:51

I have this list (List):

[\"a\", \"b\", null, \"c\", null, \"d\", \"e\"]

And I\'d like something like this:

13条回答
  •  一生所求
    2020-11-28 22:48

    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.

    • The first function creates a starting list of string lists. It specifies the result (typed) object.
    • The second function is called to process each element. It is an action on the partial result and an element.
    • The third is not really used, it comes into play on parallelising the processing, when partial results must be combined.

    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;
                        });
    
    • The first parameter is the accumulated object.
    • The second function accumulates.
    • The third is the aforementioned combiner.

提交回复
热议问题