Lambda 使用Java8流对列表项进行分组和求和

Lambda 使用Java8流对列表项进行分组和求和,lambda,collections,java-8,java-stream,Lambda,Collections,Java 8,Java Stream,假设我有一个列表。其中香蕉类定义如下: Banana.java public class Banana{ String name; Long weight; Long price; // getters & setters } 香蕉列表包含: [ {"banana1", 10, 20}, {"banana1", 10, 20}, {"banana1", 10, 20}, {"banana2", 20, 30}, {"banana

假设我有一个
列表
。其中香蕉类定义如下:

Banana.java

public class Banana{
   String name;
   Long weight;
   Long price;
   // getters & setters
}
香蕉列表包含:

[
   {"banana1", 10, 20}, 
   {"banana1", 10, 20}, 
   {"banana1", 10, 20},
   {"banana2", 20, 30},
   {"banana2", 30, 30},
   {"banana3", 50, 40},
]
我想在这里做的是按香蕉的名字分组,在其中求和权重列和价格列(每个单独),这样我可以得到以下结果:

[
   {"banana1", 30, 60}, 
   {"banana2", 50, 60},
   {"banana3", 50, 40},
]

提前感谢。

您可以使用合并功能将它们与
收集器分组。toMap

Map<String,Banana> bananasByName =
    bananas.stream()
           .collect(Collectors.toMap(Banana::getName,
                                     Function.identity(),
                                     (b1,b2)->{ 
                                                 b1.addWeightAndPrice(b2); return b1; 
                                              }));
Map bananasByName=
香蕉流
.collect(收集器).toMap(香蕉::getName,
Function.identity(),
(b1,b2)->{
b1.添加权重和价格(b2);返回b1;
}));
其中,
addweightnandprice
Banana
类的一个实例方法,它将传递的
Banana
的权重和价格添加到调用它的
Banana
实例中

如果您不想改变原始的
Banana
实例,您可以更改merge函数来创建一个新的
Banana
实例,并将两个输入
Banana
实例的权重和价格添加到该实例中。

下面的答案,以及通过以下途径测试的完整实现:


另一种解决方案与此类似: 我将解决方案简化为三个步骤。由于为它定义了
BiFunction
Function

第一个功能

BiFunction
获取两个香蕉对象并返回一个求和期望属性的香蕉对象。(价格、重量)

双功能=
(o1,o2)->新香蕉(o2.getName(),o1.getWeight()+o2.getWeight(),
o1.getPrice()+o2.getPrice());
和第二功能

    List<Banana> bananaList = bananas.stream()
            .collect(Collectors.groupingBy(Banana::getName)).values()
            .stream()
            .map(function2::apply)
            .collect(Collectors.toList());
此函数用于获取香蕉对象列表并返回单个香蕉

  Function<List<Banana>, Banana> function2 =
            l -> l.stream()
                  .reduce(new Banana("",0l,0l),(o1, o2) -> function.apply(o1, o2));
功能2=
l->l.流()
.减少(新香蕉(“,0l,0l),(o1,o2)->功能。应用(o1,o2));
最后

    List<Banana> bananaList = bananas.stream()
            .collect(Collectors.groupingBy(Banana::getName)).values()
            .stream()
            .map(function2::apply)
            .collect(Collectors.toList());
List bananaList=bananaList.stream()
.collect(Collectors.groupingBy(Banana::getName)).values()
.stream()
.map(函数2::应用)
.collect(Collectors.toList());

List bananaList=bananaList.stream()
.collect(Collectors.groupingBy(Banana::getName)).values()
.stream()
.map(巴拿大人1->巴拿大人1
.stream()
.减少(新香蕉(“、0升、0升),
(banana1,banana2)->新香蕉(banana2.getName(),
banana1.getWeight()+banana2.getWeight(),
banana1.getPrice()+banana2.getPrice())
.collect(Collectors.toList());

感谢您提供的示例,我本想对您的回答投赞成票,但不幸的是,我不能:(好吧,希望其他一些慷慨的SO用户也会这么做。Regardsless-我希望这个答案能帮助你,伙计。虽然
StringJoiner
是一个有用的工具,但与简单的
return name+”、“+weight+”、”相比,它在这里的使用并不令人信服。”+price;
@Holger:这不是主要问题,但感谢您的投入。
  Function<List<Banana>, Banana> function2 =
            l -> l.stream()
                  .reduce(new Banana("",0l,0l),(o1, o2) -> function.apply(o1, o2));
    List<Banana> bananaList = bananas.stream()
            .collect(Collectors.groupingBy(Banana::getName)).values()
            .stream()
            .map(function2::apply)
            .collect(Collectors.toList());
 List<Banana> bananaList = bananas.stream()
            .collect(Collectors.groupingBy(Banana::getName)).values()
            .stream()
            .map(bananas1 -> bananas1
                    .stream()
                    .reduce(new Banana("",0l,0l),
                            (banana1,banana2)->new Banana(banana2.getName(),
                                                 banana1.getWeight() + banana2.getWeight(),
                                                  banana1.getPrice() + banana2.getPrice())))
            .collect(Collectors.toList());