Create stream of streams from one long stream

前端 未结 4 1925
一向
一向 2020-12-10 15:31

I want to split a single Stream into a Stream of Streams based on the contents of the Streams. The resulting the St

4条回答
  •  盖世英雄少女心
    2020-12-10 16:09

    I am afraid it is not doable, at least not in a nice way. Even if you map the elements into streams and reduce them, these internal streams will have to know what elements they contain so they will have to store something.

    The simplest solution is to just use groupingBy however it will store all results in the map:

    List input = asList(1, 1, 1, 2, 2, 2, 3, 6, 7, 7, 1, 1);
    Map> grouped = input.stream().collect(groupingBy(i -> i));
    Stream> streamOfStreams = grouped.values().stream().map(list -> list.stream());
    

    You could try using reduce operation but it would require you to implement your own Stream of Streams in which you would have to store what elements every stream contains anyway. Not to mention that it would be a lot of effort to implement it.

    The best solution I can think of in your case would be to iterate over the list twice:

    public static void main(String[] args) {
        List input = asList(1, 1, 1, 2, 2, 2, 3, 6, 7, 7, 1, 1);
    
        input.stream().distinct().filter(i -> isOdd(i)).forEach(i -> {
            List subList = input.stream().filter(j -> Objects.equals(j, i)).collect(toList());
            System.out.println(subList); // do something with the stream instead of collecting to list
        });
    }
    
    private static boolean isOdd(Integer i) {
        return (i & 1) == 1;
    }
    

    Note however that it has O(n^2) time complexity.

    EDIT:

    This solution will only have local groups of elements. It stores only the current local group.

    public static void main(String[] args) {
        Stream input = Stream.of(1, 1, 1, 2, 2, 2, 3, 6, 7, 7, 1, 1);
    
        Iterator iterator = input.iterator();
        int first;
        int second = iterator.next();
    
        List buffer = new ArrayList<>();
        buffer.add(second);
    
        do {
            first = second;
            second = iterator.next();
    
            if (Objects.equals(first, second)) {
                buffer.add(second);
            } else {
                doSomethingWithTheGroup(buffer);
                buffer = new ArrayList<>(); // let GC remove the previous buffer
                buffer.add(second);
            }
        } while (iterator.hasNext());
        doSomethingWithTheGroup(buffer);
    }
    
    private static void doSomethingWithTheGroup(List buffer) {
        System.out.println(buffer);
    }
    
    private static boolean isOdd(Integer i) {
        return (i & 1) == 1;
    }
    

    output:

    [1, 1, 1]
    [2, 2, 2]
    [3]
    [6]
    [7, 7]
    [1, 1]
    

提交回复
热议问题