将列表拆分为多个列表,在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 super List > 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
您可以创建自己的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()); }