Split list into multiple lists with fixed number of elements in java 8
我想要类似于scala分组功能的东西。 基本上,一次选择2个元素并进行处理。 这是相同的参考:
将列表分为固定数量的多个列表
Lambda确实提供了诸如groupingBy和partitioningBy之类的功能,但是它们似乎都没有与Scala中的分组功能相同。 任何指针将不胜感激。
您可以使用Guava库。
List> smallerLists = Lists.partition(bigList, 10);
听起来像是一个问题,最好像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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()); } |
简单测试:
1 2 |
优点是您不需要所有项目的完整集合即可进行后续的流处理,例如
1 2 3 4 5 | chunked( IntStream.range(0, 1000).mapToObj(i -> { System.out.println("processing item"+i); return i; }), 2).anyMatch(list->list.toString().equals("[6, 7]"))); |
将打印:
1 2 3 4 5 6 7 8 9 | 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 |
而不是处理一千个
1 | chunked(Stream.iterate(0, i->i+1), 2).anyMatch(list->list.toString().equals("[6, 7]"))); |
如果您对完全实现的集合感兴趣,而不是应用后续的
1 2 3 4 5 6 7 | 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()); |
将列表转换为列表列表的递归解决方案也是可能的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | int chunkSize = 2; private < T > List<List< T >> process(List< T > list) { if (list.size() > chunkSize) { List< T > chunk = list.subList(0, chunkSize); List< T > rest = list.subList(chunkSize, list.size()); List<List< T >> lists = process(rest); return concat(chunk, lists); } else { ArrayList<List< T >> retVal = new ArrayList<>(); retVal.add(list); return retVal; } } private < T > List<List< T >> concat(List< T > chunk, List<List< T >> rest) { rest.add(0, chunk); return rest; } |
您可以创建自己的收集器。像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | class GroupingCollector< T > implements Collector<T, List<List< T >>, List<List< T >>> { private final int elementCountInGroup; public GroupingCollector(int elementCountInGroup) { this.elementCountInGroup = elementCountInGroup; } @Override public Supplier<List<List< T >>> supplier() { return ArrayList::new; } @Override public BiConsumer<List<List< T >>, T> accumulator() { return (lists, integer) -> { if (!lists.isEmpty()) { List< T > integers = lists.get(lists.size() - 1); if (integers.size() < elementCountInGroup) { integers.add(integer); return; } } List< T > list = new ArrayList<>(); list.add(integer); lists.add(list); }; } @Override public BinaryOperator<List<List< T >>> combiner() { return (lists, lists2) -> { List<List< T >> r = new ArrayList<>(); r.addAll(lists); r.addAll(lists2); return r; }; } @Override public Function<List<List< T >>, List<List< T >>> finisher() { return lists -> lists; } @Override public Set<Characteristics> characteristics() { return Collections.emptySet(); } } |
然后您可以按以下方式使用它:
1 2 | List<List<Integer>> 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]]
一个带有Java 8 Streams API的简单版本:
1 2 3 4 5 6 7 8 9 | static < T > List<List< T >> partition(List< T > 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()); } |
您可以编写自己的收藏整理器,类似于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | final List<String> strings = Arrays.asList("Hello","World","I","Am","You"); final int size = 3; final List<List<String>> stringLists = strings.stream() .collect(Collectors.collectingAndThen(Collectors.toList(), new Function<List<String>, List<List<String>>>() { @Override public List<List<String>> apply(List<String> strings) { final List<List<String>> result = new ArrayList<>(); int counter = 0; List<String> 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]] |