Java 8 - 如何对列表映射中的所有List元素求和

时间:2015-02-03 15:16:16

标签: lambda java-8 java-stream

我有一个特定对象的列表地图,我想根据特定的实例变量添加列表的所有元素。

我的对象:

class Risk{ 
    Integer id, riskValue, totRisk=0;
    String name;

    Integer getId(){
       return id;
    }
    Risk(Object[] result){
         id=(Integer)result[0];
         riskValue=(Integer)result[1];
         name=(String)result[3];
    }
}

我从数据库得到一个类型为对象的数组列表:

List< Object[] > results=getResults();

我使用Java 8按ID对我的数据进行分组,因为我希望riskValue SUM 所有类型为Risk id的对象List<Risk> risks=results.stream().map(Risk::new).collect(Collectors.toList()); Map<Integer, List<Risk>> byId=risks.stream.collect(Collectors.groupingBy(Risk::getId));

这就是我的所作所为:

riskValue

此时我按ID分组了所有Risk对象。我希望每个列表按totRisk对所有对象求和,并在变量totRisk

中得到总和

如何在变量riskValue中计算每个列表中变量List<Object[]> results的总和?

注1:我想使用Java 8,我知道如何使用Java 7及以下版本。

注2:也许也可以一次性完成,因为没有先按ID分组。我想要实现的是在原始{{1}}中对所有具有相同ID的对象求和。如果只用一个语句就可以做到更好。

1 个答案:

答案 0 :(得分:7)

您必须知道可以合并Collector。见Collectors.groupingBy(Function,Collector)

Map<Integer, Integer> byId=risks.stream.collect(
    Collectors.groupingBy(Risk::getId, Collectors.summingInt(Risk::getRiskValue)));

您也可以将它与第一个操作结合使用:

Map<Integer, Integer> byId=results.stream().map(Risk::new).collect(
    Collectors.groupingBy(Risk::getId, Collectors.summingInt(Risk::getRiskValue)));

请注意,我假设您的班级getRiskValue()中有方法Risk,否则您必须使用lambda表达式Risk::getRiskValue替换r -> r.riskValue才能访问该字段,但是,总是建议使用getter方法。

结果从id映射到total。


再次阅读您的问题之后,我发现您确实想要总结riskValue并将其存储在每个(?)totRisk实例的Risk内。这有点复杂,因为它不符合常见的使用模式:

Map<Integer, List<Risk>> byId=results.stream().map(Risk::new).collect(
  Collectors.groupingBy(Risk::getId, Collectors.collectingAndThen(
    Collectors.toList(), l-> {
      int total=l.stream().collect(Collectors.summingInt(r -> r.riskValue));
      l.forEach(r->r.totRisk=total);
      return l;
    })));

此时我们真的应该转而使用import static java.util.stream.Collectors.*;

Map<Integer, List<Risk>> byId=results.stream().map(Risk::new).collect(
  groupingBy(Risk::getId, collectingAndThen(toList(), l-> {
    int total=l.stream().collect(summingInt(r -> r.riskValue));
    l.forEach(r->r.totRisk=total);
    return l;
  })));