【问题标题】:Split a list into sublists in java using if possible flatMap [duplicate]如果可能的话,使用flatMap将列表拆分为java中的子列表[重复]
【发布时间】:2021-04-08 00:34:57
【问题描述】:

这是我的清单:

List<Integer> mylist = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12);

假设我的列表总是偶数,那么我想将它分成 6 个相等的部分。

作为草图列出:

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

输出草图:

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

如果可能的话,我更喜欢使用 Java 8 流 flatMap 的解决方案

【问题讨论】:

  • Stream-操作,就其性质而言,should be stateless。执行的任务本质上需要状态。这两个想法是冲突的。我建议不要使用Streams 来执行此任务。
  • flatMap 带走分裂;它没有把它们放进去。但更重要的是,流无法做到这一点。
  • 那我应该用什么?
  • 有很多可能性。我首先想到的是使用常规的for-loop。
  • 有没有办法用函数式编程来做到这一点?

标签: java list split functional-programming java-stream


【解决方案1】:

鉴于“子列表”的大小都相同,并且您可以将列表划分为相同大小的确切子列表,您可以计算所需的大小,然后将 IntStream 映射到每个子列表的起始索引和用它来提取它们:

List<Integer> mylist = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12);
int size = mylist.size();
int parts = 6;
int partSize = size / parts;
List<List<Integer>> result = 
    IntStream.range(0, parts)
             .mapToObj(i -> mylist.subList(i * partSize, (i + 1) * partSize)))
             .collect(Collectors.toList());

编辑:
IdeOne demo 由@Turing85 慷慨提供

【讨论】:

  • @Turing85 陷入了我自己的脑海,忘记乘以 partSize。已编辑并修复,感谢您的关注!
【解决方案2】:

我知道它超出了范围,但另一种可能性是使用像 Guava 这样的库,它有很多与 List 相关的方法。

依赖关系

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

示例

package com.stackoverflow.question;

import java.util.Arrays;
import java.util.List;

import com.google.common.collect.Lists;

public class Question {
    public static void main(String[] args) {
        List<Integer> mylist = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12);
        List<List<Integer>> partionList = Lists.partition(mylist, 2);
        
        System.out.println(partionList);
    }
}

输出

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

【讨论】:

    【解决方案3】:

    Stream-operations should be stateless。执行的任务本质上需要状态。因此,我建议不要使用Stream。相反,我会推荐一个基于for-loop 的解决方案:

    public static List<List<Integer>> partition(
            List<Integer> list, 
            int partitionSize) {
        final int listSize = list.size();
        if (listSize % partitionSize != 0) {
            throw new IllegalArgumentException("The size of the list must be "
                    + "divisible without remainder by the partition size.");
        }
        
        final List<List<Integer>> partition = new ArrayList<>();
        for (int start = 0; start < listSize; start += partitionSize) {
            partition.add(list.subList(start, start + partitionSize));
        }
        return partition;
    }
    

    Ideone demo

    如果我们坚持使用基于Stream 的实现,我建议使用Mureinikanswer 提供的代码。

    【讨论】:

      【解决方案4】:

      以下内容适用于从 1 到 size of the list 的任何组大小。如果组大小不均分列表大小,则其余部分将放入自己的组中。

      另外,额外的map(ArrayList::new) 确保子列表被放入它自己的列表中。否则,更改原始列表条目也会更改子列表条目。

      int gsize = 2;
      List<Integer> mylist =
              Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
          List<List<Integer>> subLists = IntStream
                  .iterate(0, i -> i < mylist.size(),
                          i -> i + gsize)
                  .mapToObj(i -> mylist.subList(i,
                          (i + gsize <= mylist.size()) ?
                                  i + gsize : mylist.size()))
                  .map(ArrayList::new)
                  .collect(Collectors.toList());
          
      System.out.println(subLists);
      

      打印

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

      如果组大小为 5,则新列表如下所示:

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

      【讨论】:

        【解决方案5】:

        如果您真的想要使用 flatMap 的解决方案,您可以尝试类似的方法,但不是直观的解决方案。最后它只需要返回一个Stream,所以这只是在它进行时构造子列表并在最后将它作为Stream返回。

        顺便说一句,我个人更喜欢Guava的Lists.partition

        List result = list.stream().flatMap(new Function<>() {
        
                         List<List<Integer>> mainList = new ArrayList<>();
                         List<Integer> subList = new ArrayList<>(2);
                         int index = 0;
        
                         @Override
                         public Stream<?> apply(Integer integer) {
                             subList.add(integer);
        
                             if ((index + 1) % 2 == 0) {
                                 mainList.add(subList);
                                 subList = new ArrayList<>(2);
                             }
                             index++;
                             if (index == list.size()) {
                                 if(!subList.isEmpty()) {
                                     mainList.add(subList);
                                 }
                                 return mainList.stream();
                             }
                             return Stream.empty();
                         }
        
                     }).collect(Collectors.toList());
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-09-06
          • 1970-01-01
          • 2018-05-26
          • 1970-01-01
          • 1970-01-01
          • 2010-09-29
          相关资源
          最近更新 更多