Java 8:如何将列表流式传输为列表列表?

时间:2019-06-18 13:23:24

标签: java java-8 java-stream

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

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收集器将它们分组为列表图:

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,而且我猜它是一个有序集合,因为它来自有序地图类型,所以这是我当前的解决方案:< / p>

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来实现所需的输出。那么,我该怎么做呢?

2 个答案:

答案 0 :(得分:2)

如评论中所述,指的是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);
        }

    }
}

答案 1 :(得分:0)

根据说明进行修改,以更正先前的帖子。其他答案之间的唯一区别是将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 + "}";
       }
    }