【问题标题】:How to distribute a list into sub-lists, keeping the original order of the elements?如何将列表分配到子列表中,保持元素的原始顺序?
【发布时间】:2016-10-06 15:33:56
【问题描述】:

如何将列表拆分为给定数量的列表,按顺序获取元素并将它们分配到子列表(因此不划分列表)?

我想尽可能“好”地做到这一点(使用 Java 8 功能或 Guava 或类似的东西。

  • 示例列表:[1 2 3 4 5 6 7]
  • 应该分成3个:[1 4 7][2 5][3 6]
  • 应该分成2个:[1 3 5 7][2 4 6]

【问题讨论】:

  • 元素如何分布到各自的分区?
  • @Flown 第一个元素到第一个子列表,第二个元素到第二个子列表,第三个元素到第一个子列表等(以 2 个子列表为例);只需从原始列表中按顺序将它们分配到子列表中即可

标签: java list split java-8


【解决方案1】:

如果源列表支持有效的随机访问,就像ArrayList 那样,你可以使用

IntStream.range(0, source.size()).boxed()
  .collect(groupingBy(i->i%listCount, LinkedHashMap::new, mapping(source::get, toList())));

例如

List<Integer> source=IntStream.range(0, 20).boxed().collect(toList());
System.out.println(source);
int listCount=5;

Map<Integer, List<Integer>> collect = IntStream.range(0, source.size()).boxed()
  .collect(groupingBy(i->i%listCount, LinkedHashMap::new, mapping(source::get, toList())));
// in case it really has to be a List:
List<List<Integer>> result=new ArrayList<>(collect.values());

result.forEach(System.out::println);
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[0, 5, 10, 15]
[1, 6, 11, 16]
[2, 7, 12, 17]
[3, 8, 13, 18]
[4, 9, 14, 19]

【讨论】:

  • 我喜欢这个,我一直在努力思考如何在流中保持计数
  • 您甚至可以通过使用IntStream 上的标准收集来避免对从 0 到 n 的每个整数进行装箱,尽管这似乎有点矫枉过正:.collect(LinkedHashMap::new, (m, i) -&gt; m.computeIfAbsent(i % size, k -&gt; new ArrayList&lt;&gt;()).add(list.get(i)), (m1, m2) -&gt; m2.forEach((k,v) -&gt; m1.merge(k, v, (l1,l2) -&gt; { l1.addAll(l2); return l1; })) );
  • @Alexis C:这就是我想要避免的。尤其是合并功能。可惜Map.mergeAll被遗忘了……
  • @Ash French:没有通用的干净方法来获取流中的元素位置。使用IntStream.range 并映射到元素是随机访问源的规范方式,但对于其他类型的流,你就不太走运了。
  • @Belun:收集器被设计成可组合的,虽然嵌套看起来不像操作链那样优雅,但它们更强大,因为它们是可扩展和所有其他的终端流操作可以被认为只是它们的特例。事实上,随着 Java 9 对 flatMappingfiltering 的添加,几乎每个流操作都被匹配的收集器覆盖,然后可以与其他收集器组合,最值得注意的是 groupingBy/partitioningBy...
【解决方案2】:

这样可以将所有列表放入地图中,然后您只需将子列表从地图中取出

int count = 0;
Map<Integer, List<Integer>> mapLists = list.stream()
                            .peek(i -> count ++)
                            .collect(Collectors.groupingBy(i -> count % numOfSubLists))

使用番石榴的另一种方式

https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/Lists.html#partition(java.util.List,%20int)

List<List<Integer>> lists = Lists.partition(list, noOfPartitions);

【讨论】:

  • Guava Lists.partition - 返回列表的连续子列表。不是我想要的。我需要它们以另一种方式分布。 groupBy 解决方案可能有效
  • 关于 peek 解决方案:peek 用于调试而不是弄乱数据(也许使用 map() 代替,但这不适用于外部可变变量)
  • 您也许可以摆脱 peek,只需通过执行类似 groupingBy(i -&gt; ++count % numberOfSubLists) 的操作来修改 groupingBy 中的计数
猜你喜欢
  • 2021-02-03
  • 1970-01-01
  • 1970-01-01
  • 2022-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多