Java - Stream - Collect every N elements

后端 未结 6 1256
忘掉有多难
忘掉有多难 2020-12-30 02:38

I am trying to learn java - stream. I am able to do simple iteration / filter / map / collection etc.

When I was kind of trying to collect every 3 elements and print

相关标签:
6条回答
  • 2020-12-30 03:35

    You can actually use an IntStream to simulate your list's pagination.

    List<String> list = Arrays.asList("a","b","c","d","e","f","g","h","i","j");
    
    int pageSize = 3;
    
    IntStream.range(0, (list.size() + pageSize - 1) / pageSize)
            .mapToObj(i -> list.subList(i * pageSize, Math.min(pageSize * (i + 1), list.size())))
            .forEach(System.out::println);
    

    which outputs:

    [a, b, c]
    [d, e, f]
    [g, h, i]
    [j]
    

    If you want to generate Strings, you can use String.join since you are dealing with a List<String> directly:

    .mapToObj(i -> String.join("", list.subList(i * pageSize, Math.min(pageSize * (i + 1), list.size()))))
    
    0 讨论(0)
  • 2020-12-30 03:35

    The most obvious solution:

    IntStream.range(0, list.size() / N)
             .map(i -> i * charactersAmount)
             .mapToObj(i -> list.subList(i, i + charactersAmount)
             .collect(Collectors.toWhateverYouWant());
    

    The first line - you will get a stream of ints from 0 to amount of resulting lines. From your example, list.size() / N equals 4, so stream will be 0-1-2-3.

    The second line - this stream will be mapped to the scaled by the charactersAmount one, in your case it is 3 - 0-3-6-9.

    The third line will cut sublists out of your initial list.

    The last line just treats the resulting stream as collection

    0 讨论(0)
  • 2020-12-30 03:37

    You can create your own Collector. The easiest way is to call Collector.of().

    Since your use case requires values to be processed in order, here is an implementation that simply doesn't support parallel processing.

    public static Collector<String, List<List<String>>, List<List<String>>> blockCollector(int blockSize) {
        return Collector.of(
                ArrayList<List<String>>::new,
                (list, value) -> {
                    List<String> block = (list.isEmpty() ? null : list.get(list.size() - 1));
                    if (block == null || block.size() == blockSize)
                        list.add(block = new ArrayList<>(blockSize));
                    block.add(value);
                },
                (r1, r2) -> { throw new UnsupportedOperationException("Parallel processing not supported"); }
        );
    }
    

    Test

    List<String> input = Arrays.asList("a","b","c","d","e","f","g","h","i","j");
    List<List<String>> output = input.stream().collect(blockCollector(3));
    output.forEach(System.out::println);
    

    Output

    [a, b, c]
    [d, e, f]
    [g, h, i]
    [j]
    
    0 讨论(0)
  • 2020-12-30 03:42

    If you have Guava in your project, you can use Iterables.partition method:

    import com.google.common.collect.Iterables;
    import com.google.common.collect.Streams;
    ...
    
    Stream<List<String>> stream = Streams.stream(Iterables.partition(list, 3));
    
    0 讨论(0)
  • 2020-12-30 03:42

    I solved it like this:

        List<String> list = Arrays.asList("a","b","c","d","e","f","g","h","i","j");
        int groupBy = 3;
    
        AtomicInteger index = new AtomicInteger(0);         
        Map<Integer, List<String>> groups = list.stream()
            .collect(Collectors.groupingBy(cdm -> index.getAndIncrement()/groupBy));
    
        System.out.println(groups);
    

    It prepares a map where the line number is the key and the strings on the line are in the key.

    0 讨论(0)
  • 2020-12-30 03:43

    I think the bets approach is using an amazing library StreamEx of Tagir Valeev. The solution fits in one line ))

    StreamEx.ofSubLists(list, 3).toList();
    
    0 讨论(0)
提交回复
热议问题