【问题标题】:Java8 group a list of lists to mapJava8分组要映射的列表列表
【发布时间】:2018-03-16 17:51:58
【问题描述】:

我有一个Model 和一个Property 具有以下签名的类:

public class Property {

    public String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Model {

    private List<Property> properties = new ArrayList<>();

    public List<Property> getProperties() {
        return properties;
    }
}

我想要来自List&lt;Model&gt;Map&lt;String, Set&lt;Model&gt;&gt;,其中键是来自Property 类的名称。如何使用 java8 流按其 Properyes 的名称对该列表进行分组?所有Propertyes 的名称都是唯一的。

可以在单个流中解决,还是应该以某种方式拆分它还是采用经典解决方案?

【问题讨论】:

  • @Holger 这几乎无关紧要,列表也可以。我只是放了一个 Set 以确保我不会有相同的Model 两次,因为两个模型可以在该列表中具有相同的属性。我认为这不是问题吗?
  • @Holger 我认为他的意思是“每个模型都是唯一的”,但可以有多个模型具有相同的属性。
  • @Holger 正如托比亚斯所说,抱歉不准确。
  • 没关系。你可以edit你的问题来改进它。

标签: java java-8 java-stream


【解决方案1】:
yourModels.stream()
          .flatMap(model -> model.getProperties().stream()
                  .map(property -> new AbstractMap.SimpleEntry<>(model, property.getName())))
          .collect(Collectors.groupingBy(
                Entry::getValue, 
                Collectors.mapping(
                    Entry::getKey, 
                    Collectors.toSet())));

【讨论】:

    【解决方案2】:

    为什么不使用forEach

    这是使用forEach的简洁解决方案

    Map<String, Set<Model>> resultMap = new HashMap<>();
    listOfModels.forEach(currentModel ->
            currentModel.getProperties().forEach(prop -> {
                Set<Model> setOfModels = resultMap.getOrDefault(prop.getName(), new HashSet<>());
                setOfModels.add(currentModel);
                resultMap.put(prop.getName(), setOfModels);
            })
    ); 
    

    【讨论】:

    • 我认为在这里使用foreach 确实更简单(只是想发布相同的内容),但不是getOrDefault 然后put,我建议使用computeIfAbsent:@987654328 @
    • @tobias_k 我想编辑同样的东西... :) 是的 computeIfAbsent 是一个很好的建议
    • 是的,这是我在找不到任何“单流”解决方案后的第二种方法。确实,它比您的答案@Eugene 更简单,并且可能更具可读性,但我会接受您的答案,因为这最适合这个问题。
    • @Sunflame 可读是基于意见的,我实际上更容易阅读流方法......但这是一个品味问题
    • @Eugene 好吧,你可以把forEach 解决方案的逻辑变成流解决方案:Map&lt;String, Set&lt;Model&gt;&gt; resultMap = listOfModels.stream().collect(HashMap::new, (map,model) -&gt; model.getProperties().forEach(p -&gt; map.computeIfAbsent(p.getName(),x-&gt;new HashSet&lt;&gt;()) .add(model)), (m1,m2)-&gt;m2.forEach((k,v) -&gt; m1.merge(k, v, (s1,s2) -&gt; { s1.addAll(s2); return s1; })));
    猜你喜欢
    • 2018-11-13
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多