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

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

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

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

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

 public static  Stream> chunked(Stream s, int chunkSize) { if(chunkSize<1) throw new IllegalArgumentException("chunkSize=="+chunkSize); if(chunkSize==1) return s.map(Collections::singletonList); Spliterator 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>(size, ch) { private List current; @Override public boolean tryAdvance(Consumer> action) { if(current==null) current=new ArrayList<>(chunkSize); while(current.size() 

简单测试:

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

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

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

将打印:

 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 

而不是处理一千个IntStream.range(0, 1000)项( IntStream.range(0, 1000) 。 这也使得能够使用无限源流:

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

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

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

您可以使用Guava库。

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

您可以创建自己的collections家。 像这样的东西:

 class GroupingCollector implements Collector>, List>> { private final int elementCountInGroup; public GroupingCollector(int elementCountInGroup) { this.elementCountInGroup = elementCountInGroup; } @Override public Supplier>> supplier() { return ArrayList::new; } @Override public BiConsumer>, T> accumulator() { return (lists, integer) -> { if (!lists.isEmpty()) { List integers = lists.get(lists.size() - 1); if (integers.size() < elementCountInGroup) { integers.add(integer); return; } } List list = new ArrayList<>(); list.add(integer); lists.add(list); }; } @Override public BinaryOperator>> combiner() { return (lists, lists2) -> { List> r = new ArrayList<>(); r.addAll(lists); r.addAll(lists2); return r; }; } @Override public Function>, List>> finisher() { return lists -> lists; } @Override public Set characteristics() { return Collections.emptySet(); } } 

然后你可以用这样的方式使用它:

  List> collect = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).collect(new GroupingCollector<>(3)); System.out.println(collect); 

将打印:

[[1,2,3],[4,5,6],[7,8,9],[10]]

将列表转换为列表列表的递归解决方案也是可能的

 int chunkSize = 2; private  List> process(List list) { if (list.size() > chunkSize) { List chunk = list.subList(0, chunkSize); List rest = list.subList(chunkSize, list.size()); List> lists = process(rest); return concat(chunk, lists); } else { ArrayList> retVal = new ArrayList<>(); retVal.add(list); return retVal; } } private  List> concat(List chunk, List> rest) { rest.add(0, chunk); return rest; } 

你可以编写自己的collections家修整器,类似于

 final List strings = Arrays.asList("Hello", "World", "I", "Am", "You"); final int size = 3; final List> stringLists = strings.stream() .collect(Collectors.collectingAndThen(Collectors.toList(), new Function, List>>() { @Override public List> apply(List strings) { final List> result = new ArrayList<>(); int counter = 0; List stringsToAdd = new ArrayList<>(); for (final String string : strings) { if (counter == 0) { result.add(stringsToAdd); } else { if (counter == size) { stringsToAdd = new ArrayList<>(); result.add(stringsToAdd); counter = 0; } } ++counter; stringsToAdd.add(string); } return result; } })); System.out.println("stringLists = " + stringLists); // stringLists = [[Hello, World, I], [Am, You]] 

一个简单版本的java 8流api:

 static  List> partition(List list, Integer partitionSize) { int numberOfLists = BigDecimal.valueOf(list.size()) .divide(BigDecimal.valueOf(partitionSize), 0, CEILING) .intValue(); return IntStream.range(0, numberOfLists) .mapToObj(it -> list.subList(it * partitionSize, Math.min((it+1) * partitionSize, list.size()))) .collect(Collectors.toList()); }