【问题标题】:Java 8: How to stream a list into a list of lists?Java 8:如何将列表流式传输到列表列表中?
【发布时间】:2019-06-18 13:23:24
【问题描述】:

给定需要排序和分组的对象列表:

static class Widget {
    // ...
    public String getCode() { return widgetCode; }
    public String getName() { return widgetName; }
}

List<Widget> widgetList = Arrays.asList(
    // several widgets with codes and names
);

我想将列表分组为一个列表列表,按 widgetCode 分组,每个子列表的元素按照它们在原始列表中遇到的顺序排列。我知道我可以使用groupingBy Collector 将它们分组到列表地图中:

Map<String,List<Widget>> widgetMap = widgetList.stream()
    .collect(groupingBy(Widget::getCode));

我不认为键是排序的,所以我采取了额外的步骤,将整个内容加载到 SortedMap 类型中:

SortedMap<String,List<Widget>> sortedWidgetMap = new TreeMap<String,List<Widget>>(
    widgetList.stream()
        .collect(groupingBy(Widget::getCode))
);

我知道我可以使用 .values() 从 sortedWidgetMap 中获取一个集合,我猜它是一个有序集合,因为它来自一个有序的地图类型,所以这是我目前的解决方案:

Collection<List<Widget>> widgetListList = new TreeMap<String,List<Widget>>(
    widgetList.stream()
        .collect(groupingBy(Widget::getCode))
).values();
widgetListList.forEach(System.out::println);  // do something with the data

到目前为止,这有效,但我不确定生成的 widgetListList 实际上是否保证顺序正确(即通过 widgetCode)或者子列表将构建在在原始列表中找到它们的顺序。另外,我认为必须可以单独使用 Stream API 来实现我想要的输出。那么,我怎样才能做得更好呢?

【问题讨论】:

  • 对于排序,你可以给TreeMap一个Comparator排序。
  • 来自SortedMap.values()的javadoc:“集合的迭代器以相应键的升序返回值。”,所以不用担心你的解决方案的顺序(虽然效率可能会提高)
  • 好吧,您可以向groupingBy 提供排序后的地图,例如喜欢这里:stackoverflow.com/questions/35116264/…

标签: java java-8 java-stream


【解决方案1】:

正如评论中提到的,指的是question that is very similar(事实上,我几乎认为它是重复的......),groupBy 调用有不同的风格,其中一个允许传入一个要创建的地图的工厂。

因此无需将“简单”groupBy 调用的结果显式包装到新的TreeMap 的创建中,因为您可以直接创建TreeMap。此地图(及其values() 集合!)将按键排序。地图的值是列表,它们是使用下游收集器toList() 创建的,它明确表示它将按照遇到的顺序收集结果

所以下面确实应该是一个简单、正确、高效的解决方案:

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class CollectToListOfList {
    static class Widget {
        String code;
        String name;

        Widget(String code, String name) {
            this.code = code;
            this.name = name;
        }

        public String getCode() {
            return code;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return code + ": " + name;
        }

    }

    public static void main(String[] args) {
        List<Widget> widgetList = Arrays.asList(
            new Widget("0", "A"), 
            new Widget("1", "B"), 
            new Widget("2", "C"),
            new Widget("3", "D"), 
            new Widget("0", "E"), 
            new Widget("1", "F"), 
            new Widget("2", "G"),
            new Widget("3", "H"), 
            new Widget("0", "I"), 
            new Widget("1", "J"));

        Collection<List<Widget>> result = widgetList.stream()
            .collect(Collectors.groupingBy(Widget::getCode, TreeMap::new, Collectors.toList()))
            .values();

        for (List<Widget> list : result) {
            System.out.println(list);
        }

    }
}

【讨论】:

    【解决方案2】:

    根据说明进行了编辑以更正以前的帖子。其他人的答案之间的唯一区别是 values() 结果被输入到 ArrayList 构造函数中以创建列表列表。

          // Create some data
          Random r = new Random(29);
          String codes = "ABCD";
          List<Widget> widgetList = r.ints(10, 0, 4).mapToObj(
                n -> new Widget(codes.substring(n, n + 1), "N" + i++)).collect(
                      Collectors.toList());
    
          // Now create the list of lists.
    
          List<List<Widget>> listofWidgets = new ArrayList<>(
                widgetList.stream().collect(Collectors.groupingBy(Widget::getCode,
                      TreeMap::new,
                      Collectors.toList())).values());
    
          // Display them
          for (List<?> list : listofWidgets) {
             System.out.println(list);
          }
    
    

    小部件类

    
        class Widget {
           String widgetCode;
           String widgetName;
    
           public Widget(String wc, String wn) {
              widgetCode = wc;
              widgetName = wn;
           }
    
           public String getCode() {
              return widgetCode;
           }
    
           public String getName() {
              return widgetName;
           }
    
           public String toString() {
              return "{" + widgetCode + ":" + widgetName + "}";
           }
        }
    
    

    【讨论】:

    • 不,那不是我的目标。我想要的是 List 的列表。 List 中的第一个元素是所有 的 List,其中 widgetCode 为“A”,第二个元素是所有 的 List,其中 widgetCode 为“B”,以此类推。也许我的玩具问题太傻了,说不清楚!
    • 你的问题很好。显然我是唯一一个不明白的人。感谢您的澄清。
    猜你喜欢
    • 1970-01-01
    • 2021-01-18
    • 2017-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 1970-01-01
    相关资源
    最近更新 更多