Java - Stream - 收集每N个元素

时间:2017-03-27 22:45:30

标签: java java-8 java-stream

我正在尝试学习java - stream。我能够做简单的迭代/过滤/地图/收集等。

当我试图收集每个3个元素并打印时,如本例所示,[收集每3个元素并打印等等...]

if ( scanf( " %c", coin ) == 1 )
{
    //...

输出:

    List<String> list = Arrays.asList("a","b","c","d","e","f","g","h","i","j");

    int count=0;
    String append="";
    for(String l: list){
        if(count>2){
            System.out.println(append);
            System.out.println("-------------------");
            append="";
            count=0;
        }
        append = append + l;
        count++;
    }
    System.out.println(append);

我没有得到任何关于如何使用流这样做的线索。我应该实现自己的收藏家来实现这个目标吗?

6 个答案:

答案 0 :(得分:16)

您实际上可以使用IntStream来模拟列表的分页。

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);

输出:

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

如果您想生成字符串,可以使用String.join,因为您直接处理List<String>

.mapToObj(i -> String.join("", list.subList(i * pageSize, Math.min(pageSize * (i + 1), list.size()))))

答案 1 :(得分:9)

您可以创建自己的Collector。最简单的方法是致电Collector.of()

由于您的用例需要按顺序处理值,因此这是一个不支持并行处理的实现。

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"); }
    );
}

测试

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);

输出

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

答案 2 :(得分:8)

如果您的项目中有Guava,则可以使用Iterables.partition方法:

import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
...

Stream<List<String>> stream = Streams.stream(Iterables.partition(list, 3));

答案 3 :(得分:5)

我解决了这个问题:

    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);

它准备一个地图,其中行号是键,行上的字符串在键中。

答案 4 :(得分:2)

我认为投注方法是使用StreamEx的惊人库Tagir Valeev。解决方案适合一行))

StreamEx.ofSubLists(list, 3).toList();

答案 5 :(得分:1)

最明显的解决方案:

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

第一行-您将获得一个从0到结果行数的整数流。在您的示例中,list.size()/ N等于4,因此流将为0-1-2-3。

第二行-该流将映射到由characterAmount缩放的比例,在您的情况下为3-0-3-6-9。

第三行将从您的初始列表中删除子列表。

最后一行仅将结果流视为集合