将列表拆分为多个列表,在java 8中具有固定数量的元素

vam*_*afa 12 java scala java-8

我想要一些类似于scala分组函数的东西.基本上,一次挑选2个元素并处理它们.以下是相同的参考:

将列表拆分为具有固定数量元素的多个列表

Lambdas确实提供了诸如groupingBy和partitioningBy之类的东西,但它们似乎都没有像Scala中的分组函数那样做.任何指针将不胜感激.

小智 27

您可以使用Guava库.

List<Integer> bigList = ... List<List<Integer>> smallerLists = Lists.partition(bigList, 10);


Hol*_*ger 16

这听起来像一个问题,像低级Stream操作一样处理得更好,就像StreamAPI本身提供的操作一样.一个(相对)简单的解决方案可能如下所示:

public static <T> Stream<List<T>> chunked(Stream<T> s, int chunkSize) {
    if(chunkSize<1) throw new IllegalArgumentException("chunkSize=="+chunkSize);
    if(chunkSize==1) return s.map(Collections::singletonList);
    Spliterator<T> src=s.spliterator();
    long size=src.estimateSize();
    if(size!=Long.MAX_VALUE) size=(size+chunkSize-1)/chunkSize;
    int ch=src.characteristics();
    ch&=Spliterator.SIZED|Spliterator.ORDERED|Spliterator.DISTINCT|Spliterator.IMMUTABLE;
    ch|=Spliterator.NONNULL;
    return StreamSupport.stream(new Spliterators.AbstractSpliterator<List<T>>(size, ch)
    {
        private List<T> current;
        @Override
        public boolean tryAdvance(Consumer<? super List<T>> action) {
            if(current==null) current=new ArrayList<>(chunkSize);
            while(current.size()<chunkSize && src.tryAdvance(current::add));
            if(!current.isEmpty()) {
                action.accept(current);
                current=null;
                return true;
            }
            return false;
        }
    }, s.isParallel());
}
Run Code Online (Sandbox Code Playgroud)

简单测试:

chunked(Stream.of(1, 2, 3, 4, 5, 6, 7), 3)
  .parallel().forEachOrdered(System.out::println);
Run Code Online (Sandbox Code Playgroud)

优点是您不需要为后续流处理提供所有项目的完整集合,例如

chunked(
    IntStream.range(0, 1000).mapToObj(i -> {
        System.out.println("processing item "+i);
        return i;
    }), 2).anyMatch(list->list.toString().equals("[6, 7]")));
Run Code Online (Sandbox Code Playgroud)

将打印:

processing item 0
processing item 1
processing item 2
processing item 3
processing item 4
processing item 5
processing item 6
processing item 7
true
Run Code Online (Sandbox Code Playgroud)

而不是处理一千个项目IntStream.range(0, 1000).这也可以使用无限源Stream:

chunked(Stream.iterate(0, i->i+1), 2).anyMatch(list->list.toString().equals("[6, 7]")));
Run Code Online (Sandbox Code Playgroud)

如果您对完全物化的集合感兴趣而不是应用后续Stream操作,则可以使用以下操作:

List<Integer> list=Arrays.asList(1, 2, 3, 4, 5, 6, 7);
int listSize=list.size(), chunkSize=2;
List<List<Integer>> list2=
    IntStream.range(0, (listSize-1)/chunkSize+1)
             .mapToObj(i->list.subList(i*=chunkSize,
                                       listSize-chunkSize>=i? i+chunkSize: listSize))
             .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • @Lyubomyr Shaydariv:的确,这是一个不同的问题.这个答案的重点是提供一个返回Stream的操作,该操作可用于链接更多Stream操作,保持懒惰."collect"操作是终端操作,启动实际处理.这样的"收集器"应该是可能的,我很安静,这样的解决方案已经存在于SO上. (2认同)