【问题标题】:Java 8 groupingBy for a list of MapsJava 8 groupingBy 用于地图列表
【发布时间】:2020-03-30 12:51:45
【问题描述】:

我有一个地图列表,我想按名称对其进行分组

List<Map> allObjs = new ArrayList<Map>();
Map<String, Object> src = new HashMap();
src.put("name", "asset1");
src.put("description", "desc1" );
src.put("definition", "def1" );

Map<String, Object> src2 = new HashMap();
src2.put("name", "asset1");
src2.put("description", "desc2" );
src2.put("definition", "def2" );
allObjs.add(src);
allObjs.add(src2);

我尝试将它们分组

Map<Object, List<Map>> result = allObjs.stream().collect(Collectors.groupingBy(p -> p.get("name")));

我想要的是

{
 name=asset1,
 description=["desc1","desc2"],
 definition=["def1","def2"]
}

我希望将所有其他键分组到一个列表中 但我得到的是

{asset1=[
            {name=asset1, description=desc1, definition=def2},
            {name=asset1, description=desc2, definition=def2}
        ]
}

我如何将除 name 之外的所有其他键分组到上面预期的列表中?

【问题讨论】:

  • groupingBy 将根据键对列表中的项目进行分组。它不会合并两个地图

标签: java java-8 hashmap java-stream groupingby


【解决方案1】:

您可以使用groupBymapping 来获得所需的结果,只是值只能是单一类型,

Map<String, Set<String>> collect1 = allObjs.stream()
                .flatMap(m -> m.entrySet().stream())
                .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toSet())));

结果:

{
 name=[asset1],
 description=[desc1,desc2],
 definition=[def1,def2]
}

【讨论】:

    【解决方案2】:

    groupingBy 将根据键对项目进行分组。它不会合并两个地图。这是实现你想要的丑陋方式之一。

    给定

    List<Map<String, String>> allObjs = new ArrayList<>();
    Map<String, String> src = new HashMap();
    src.put("name", "asset1");
    src.put("description", "desc1" );
    src.put("definition", "def1" );
    
    Map<String, String> src2 = new HashMap();
    src2.put("name", "asset1");
    src2.put("description", "desc2" );
    src2.put("definition", "def2" );
    allObjs.add(src);
    allObjs.add(src2);
    

    一种方法是这样。创建两个类,分别代表现有结构和最终输出结构

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public class SomeClass {
        private String name;
        private String description;
        private String definition;
    }
    
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public class NewClass {
        private String name;
        private List<String> description;
        private List<String> definition;
    }
    

    那么这段代码应该得到你想要的输出

    final List<NewClass> collect = allObjs.stream()
            .map(entry -> new SomeClass(entry.get("name"), entry.get("description"), entry.get("definition")))
            .collect(Collectors.toList())
            .stream()
            .collect(Collectors.groupingBy(SomeClass::getName))
            .entrySet()
            .stream()
            .map(entry -> {
                final List<String> descriptions = entry.getValue().stream().map(SomeClass::getDescription).collect(Collectors.toList());
                final List<String> definitions = entry.getValue().stream().map(SomeClass::getDefinition).collect(Collectors.toList());
                return new NewClass(entry.getKey(), descriptions, definitions);
            }).collect(Collectors.toList());
    

    最终结果将是一个 NewClass 类型的列表。列表中的每个条目都将具有具有唯一键的所需输出。您需要加入大量空值检查,因为它是我们正在处理的 Map。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-24
      • 1970-01-01
      • 2015-09-01
      • 2017-05-23
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      • 2021-01-16
      相关资源
      最近更新 更多