分组和求和对象(如带有Java Lambda的SQL中的对象)?
我有一个Foo与这些领域的课程:
id:int /名称;字符串/ targetCost:BigDecimal / actualCost:BigDecimal
我得到了此类对象的数组列表。例如:
new Foo(1, "P1", 300, 400), new Foo(2, "P2", 600, 400),
new Foo(3, "P3", 30, 20),
new Foo(3, "P3", 70, 20),
new Foo(1, "P1", 360, 40),
new Foo(4, "P4", 320, 200),
new Foo(4, "P4", 500, 900)
我想通过创建“ targetCost”和“ actualCost”的总和并将“行”分组来转换这些值
new Foo(1, "P1", 660, 440),new Foo(2, "P2", 600, 400),
new Foo(3, "P3", 100, 40),
new Foo(4, "P4", 820, 1100)
我现在写的是:
data.stream() .???
.collect(Collectors.groupingBy(PlannedProjectPOJO::getId));
我怎样才能做到这一点?
回答:
使用Collectors.groupingBy
是正确的方法,但不要使用单个参数版本来创建每个组的所有项目列表,而应使用两个arg版本,后者使用另一个参数版本Collector来确定如何汇总每个组的元素。
当您要汇总元素的单个属性或仅计算每个组中元素的数量时,这特别平滑:
数数:
list.stream() .collect(Collectors.groupingBy(foo -> foo.id, Collectors.counting()))
.forEach((id,count)->System.out.println(id+"\t"+count));
总结一个属性:
list.stream() .collect(Collectors.groupingBy(foo -> foo.id,
Collectors.summingInt(foo->foo.targetCost)))
.forEach((id,sumTargetCost)->System.out.println(id+"\t"+sumTargetCost));
在您要聚合多个属性的情况下,指定一种自定义归约操作(如此答案中所建议的那样)是正确的方法,但是,您可以在分组操作期间执行归约操作,因此无需将整个数据收集到Map<…,List>执行还原之前的a :
(我假设您import static java.util.stream.Collectors.*;
现在使用…)
list.stream().collect(groupingBy(foo -> foo.id, collectingAndThen(reducing( (a,b)-> new Foo(a.id, a.ref, a.targetCost+b.targetCost, a.actualCost+b.actualCost)),
Optional::get)))
.forEach((id,foo)->System.out.println(foo));
为了完整起见,这里是一个超出您问题范围的问题的解决方案:如果要GROUP BY多个列/属性该怎么办?
跳入程序员头脑的第一件事是用来groupingBy提取流元素的属性并创建/返回新的关键对象。但这要求键属性具有适当的holder类(而Java没有通用的Tuple类)。
但是还有另一种选择。通过使用三参数形式,groupingBy我们可以为实际Map实现指定供应商,该供应商将确定键的相等性。通过使用带有比较器比较多个属性的排序映射,我们无需其他类即可获得所需的行为。我们只需要注意不要使用比较器忽略的关键实例中的属性,因为它们只有任意值:
list.stream().collect(groupingBy(Function.identity(), ()->new TreeMap<>(
// we are effectively grouping by [id, actualCost]
Comparator.<Foo,Integer>comparing(foo->foo.id).thenComparing(foo->foo.actualCost)
), // and aggregating/ summing targetCost
Collectors.summingInt(foo->foo.targetCost)))
.forEach((group,targetCostSum) ->
// take the id and actualCost from the group and actualCost from aggregation
System.out.println(group.id+"\t"+group.actualCost+"\t"+targetCostSum));
以上是 分组和求和对象(如带有Java Lambda的SQL中的对象)? 的全部内容, 来源链接: utcz.com/qa/414936.html