代码之家  ›  专栏  ›  技术社区  ›  vvra

对象- Java流分组

  •  3
  • vvra  · 技术社区  · 6 年前

    我有一个数据列表,如下所示:

    List<Data> data = new ArrayList<Data>();
    data.add(new Data("d1", "option1"));
    data.add(new Data("d2", "option1"));
    data.add(new Data("d1", "option2"));
    data.add(new Data("d3", "option1"));
    data.add(new Data("d3", "option2"));
    data.add(new Data("d3", "option3"));
    

    结构如下:

    class Data {
        private String name;
        private String option;
        private List<String> options = new ArrayList<>();
        public Data(String name, String option) {
            this.name = name;
            this.option = option;
        }
    
        public void addOption(String option) {
            options.add(option);
        }
    }
    

    如何根据名称及其选项将项分组到新数组,

    [
    "d1": {
        "name": "d1",
        "options": ["option1", "option2"]
    },
    "d2": {
        "name": "d2",
        "options": ["option1"]
    },
    "d3": {
        "name": "d3",
        "options": ["option1", "option2", "option3"]
    }
    ]
    
    3 回复  |  直到 6 年前
        1
  •  2
  •   Eran    6 年前

    你可以用 Collectors.toMap 收藏家:

    Map<String,Data>
        grouped = data.stream()
                      .collect(Collectors.toMap(Data::getName,
                                                d -> new Data(d.getName(),d.getOption()),
                                                (d1,d2) -> {d1.addOptions(d2.getOptions()); return d1;});
    

    这需要更改 Data 构造函数将传递的选项添加到选项中 List 以及添加 addOptions 方法,该方法接收选项列表并将所有选项添加到选项中。 当前实例的。

        2
  •  1
  •   ernest_k    6 年前

    可以在流上使用简单的分组收集器:

    Map<String, List<String>> optionMap = data.stream()
                .collect(Collectors.groupingBy(Data::getName, 
                         Collectors.mapping(Data::getOption, Collectors.toList())));
    

    当使用测试列表进行测试时,上面的内容会产生以下输出:

    {d1=[option1, option2], d2=[option1], d3=[option1, option2, option3]}
    

    上面看起来是一个更好的,类型安全的替代你想要的地图。此外,它避免了不必要的重复。

    但是,最终的地图可以根据上述内容进行计算:

    Map<String, Map<String, Object>> m = new HashMap<>();
    optionMap.entrySet().forEach(entry -> {
        Map<String, Object> map = new HashMap<>();
        map.put("name", entry.getKey());
        map.put("options", entry.getValue());
    
        m.put(entry.getKey(), map);
    });
    

    这个 m 上面的地图看起来像:

    {d1={name=d1, options=[option1, option2]}, 
     d2={name=d2, options=[option1]}, 
     d3={name=d3, options=[option1, option2, option3]}}
    

    这是您所需要的,但它似乎包含重复的数据,而且它的类型安全性比前面结果中的简单映射要低。

        3
  •  1
  •   Ravindra Ranwala    6 年前

    试试这个,

    final Map<String, List<String>> optionsByName = dataList.stream().collect(
            Collectors.groupingBy(Data::getName, Collectors.mapping(Data::getOption, Collectors.toList())));
    

    我建议你用这个 map 作为创建所需dto的源代码,而不必为了得到所需的准确结果而弄乱代码。