【问题标题】:How can I turn a List of Lists into a List in Java 8?如何将列表列表转换为 Java 8 中的列表?
【发布时间】:2014-09-28 14:29:47
【问题描述】:

如果我有一个List<List<Object>>,如何使用 Java 8 的功能将其转换为包含相同迭代顺序的所有对象的List<Object>

【问题讨论】:

    标签: java collections java-8


    【解决方案1】:

    您可以使用flatMap 将内部列表(在将它们转换为Streams之后)扁平化为单个Stream,然后将结果收集到一个列表中:

    List<List<Object>> list = ...
    List<Object> flat = 
        list.stream()
            .flatMap(List::stream)
            .collect(Collectors.toList());
    

    【讨论】:

    • @arshajii true,但出于某种原因,我更喜欢 lambda 表达式。也许我不喜欢:: 的样子:)
    • Class::method 起初感觉有点奇怪,但它的好处是它声明了你映射的对象类型。这是你在流中失去的东西。
    • 但您可能希望拥有一个 List 容器,在这种情况下您可能需要使用 lambda (l->l.myList.stream())。
    • 如果您需要进行显式转换(例如,将基元数组转换为 List),那么可能还需要 lambda。
    【解决方案2】:

    flatmap 更好,但还有其他方法可以达到同样的效果

    List<List<Object>> listOfList = ... // fill
    
    List<Object> collect = 
          listOfList.stream()
                    .collect(ArrayList::new, List::addAll, List::addAll);
    

    【讨论】:

    • 请注意,使用 flatMap 您不会关闭流,因为使用 collect 需要再次重新打开它。
    【解决方案3】:

    Stream 上的 flatMap 方法当然可以为您展平这些列表,但它必须为元素创建 Stream 对象,然后为结果创建 Stream

    您不需要所有这些 Stream 对象。这是执行任务的简单、简洁的代码。

    // listOfLists is a List<List<Object>>.
    List<Object> result = new ArrayList<>();
    listOfLists.forEach(result::addAll);
    

    因为ListIterable,所以这段代码调用the forEach method(Java 8 特性),它继承自Iterable

    Iterable 的每个元素执行给定的操作,直到所有元素都已处理完毕或该操作引发异常。如果指定了迭代顺序,则按迭代顺序执行操作。

    ListIterator 按顺序返回项目。

    对于Consumer,此代码将方法引用(Java 8 特性)传递给Java 8 之前的方法List.addAll,以按顺序添加内部列表元素。

    将指定集合中的所有元素附加到此列表的末尾,按照指定集合的​​迭代器返回的顺序(可选操作)。

    【讨论】:

    • 很好的替代建议,可以避免一些不必要的分配。在处理一些较大的集合时,看看它的顶部堆使用情况会很有趣,看看它们是如何相互比较的。
    【解决方案4】:

    正如@Saravana 提到的:

    平面图更好,但还有其他方法可以达到同样的效果

     listStream.reduce(new ArrayList<>(), (l1, l2) -> {
            l1.addAll(l2);
            return l1;
     });
    

    总结起来,有如下几种方式可以实现:

    private <T> List<T> mergeOne(Stream<List<T>> listStream) {
        return listStream.flatMap(List::stream).collect(toList());
    }
    
    private <T> List<T> mergeTwo(Stream<List<T>> listStream) {
        List<T> result = new ArrayList<>();
        listStream.forEach(result::addAll);
        return result;
    }
    
    private <T> List<T> mergeThree(Stream<List<T>> listStream) {
        return listStream.reduce(new ArrayList<>(), (l1, l2) -> {
            l1.addAll(l2);
            return l1;
        });
    }
    
    private <T> List<T> mergeFour(Stream<List<T>> listStream) {
        return listStream.reduce((l1, l2) -> {
            List<T> l = new ArrayList<>(l1);
            l.addAll(l2);
            return l;
        }).orElse(new ArrayList<>());
    }
    
    private <T> List<T> mergeFive(Stream<List<T>> listStream) {
        return listStream.collect(ArrayList::new, List::addAll, List::addAll);
    }
    

    【讨论】:

      【解决方案5】:

      List&lt;List&gt; 转换为List 的方法:

      listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
      

      看这个例子:

      public class Example {
      
          public static void main(String[] args) {
              List<List<String>> listOfLists = Collections.singletonList(Arrays.asList("a", "b", "v"));
              List<String> list = listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
      
              System.out.println("listOfLists => " + listOfLists);
              System.out.println("list => " + list);
          }
      
      }       
      

      打印出来:

      listOfLists => [[a, b, c]]
      list => [a, b, c]
      

      在 Python 中,这可以使用列表理解来完成。

      list_of_lists = [['Roopa','Roopi','Tabu', 'Soudipta'],[180.0, 1231, 2112, 3112], [130], [158.2], [220.2]]
      
      flatten = [val for sublist in list_of_lists for val in sublist]
      
      print(flatten)
      
      ['Roopa', 'Roopi', 'Tabu', 'Soudipta', 180.0, 1231, 2112, 3112, 130, 158.2, 220.2]
      

      【讨论】:

      • 这应该被标记为正确答案
      【解决方案6】:

      您可以使用Eclipse Collections 中的flatCollect() 模式。

      MutableList<List<Object>> list = Lists.mutable.empty();
      MutableList<Object> flat = list.flatCollect(each -> each);
      

      如果您无法从List 更改列表:

      List<List<Object>> list = new ArrayList<>();
      List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);
      

      注意:我是 Eclipse Collections 的贡献者。

      【讨论】:

      • 当Java 8提供功能时,为什么要使用第三方依赖?
      • Eclipse Collections API 在集合本身上,所以代码简洁,是本例的主要原因之一。
      【解决方案7】:

      我只是想再解释一个场景,比如List&lt;Documents&gt;,这个列表包含更多其他文档的列表,比如List&lt;Excel&gt;List&lt;Word&gt;List&lt;PowerPoint&gt;。所以结构是

      class A {
        List<Documents> documentList;
      }
      
      class Documents {
        List<Excel> excels;
        List<Word> words;
        List<PowerPoint> ppt;
      }
      

      现在,如果您只想从文档中迭代 Excel,请执行以下操作..

      所以代码是

       List<Documents> documentList = new A().getDocumentList();
      
       //check documentList as not null
      
       Optional<Excel> excelOptional = documentList.stream()
                               .map(doc -> doc.getExcel())
                               .flatMap(List::stream).findFirst();
       if(excelOptional.isPresent()){
         Excel exl = optionalExcel.get();
         // now get the value what you want.
       }
      

      我希望这可以解决某人在编码时遇到的问题...

      【讨论】:

        【解决方案8】:

        Eran 的答案是最佳答案的扩展,如果您有一堆列表层,您可以继续对它们进行平面映射。

        这还提供了一种方便的过滤方式,如果需要,您还可以向下层进行过滤。

        例如:

        List<List<List<List<List<List<Object>>>>>> multiLayeredList = ...
        
        List<Object> objectList = multiLayeredList
            .stream()
            .flatmap(someList1 -> someList1
                .stream()
                .filter(...Optional...))
            .flatmap(someList2 -> someList2
                .stream()
                .filter(...Optional...))
            .flatmap(someList3 -> someList3
                .stream()
                .filter(...Optional...))
            ...
            .collect(Collectors.toList())
        

        这在 SQL 中类似于在 SELECT 语句中包含 SELECT 语句。

        【讨论】:

        • 为什么不使用递归? :)
        • 根据我多年的经验,Java 等语言中的递归是危险的,因为它很容易意外吃掉系统的所有资源。你可以做到,但我不会。但也许另一种选择是使用循环来构建嵌套流,然后运行该流。根据我的理解,您不能真正在流中实现无限循环。
        【解决方案9】:

        我们可以使用平面地图,请参考以下代码:

         List<Integer> i1= Arrays.asList(1, 2, 3, 4);
         List<Integer> i2= Arrays.asList(5, 6, 7, 8);
        
         List<List<Integer>> ii= Arrays.asList(i1, i2);
         System.out.println("List<List<Integer>>"+ii);
         List<Integer> flat=ii.stream().flatMap(l-> l.stream()).collect(Collectors.toList());
         System.out.println("Flattened to List<Integer>"+flat);
        

        【讨论】:

          【解决方案10】:

          由于,您可以使用Stream#mapMulti

          List<Object> result = listOfLists.stream()
                                           .mapMulti((List<Object> list, Consumer<Object> consumer) -> {
                                               list.forEach(consumer::accept);
                                           })
                                           .collect(Collectors.toList());
          

          如果您需要不可变的List,您甚至可以使用toList() 作为终端操作

          List<Object> result = listOfLists.stream()
                                           .mapMulti((List<Object> list, Consumer<Object> consumer) -> {
                                               list.forEach(consumer::accept);
                                           })
                                           .toList();
          

          【讨论】:

            【解决方案11】:

            List list = map.values().stream().collect(Collectors.toList());

                List<Employee> employees2 = new ArrayList<>();
                
                 list.stream().forEach(
                         
                         n-> employees2.addAll(n));
            

            【讨论】:

            • 假设我在上面的代码中有 List>
            • 请阅读this帮助页面,了解如何正确格式化代码。此外,您可以随时edit您的答案,而不是发布后续 cmets。
            • 虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的答案添加解释并说明适用的限制和假设。
            • 感谢 Yunnosch 的建议..我会做的..快乐编码!
            猜你喜欢
            • 1970-01-01
            • 2014-07-03
            • 2015-06-20
            • 2018-04-05
            • 2019-02-24
            • 1970-01-01
            • 2015-03-26
            • 2018-10-23
            • 1970-01-01
            相关资源
            最近更新 更多