我需要在lambda中执行以下操作,但无法想到单流和减少可以帮助的方式:(
我有Employee ArrayList,其中<strong> name 成员变量可以在列表中的对象之间重复。我需要创建一个地图,其中key是员工姓名,value是对象,其中我们有该员工的cost1和cost2的总和。
员工类有 - &gt;字符串名称,整数cost1,整数cost2
输出类有 - &gt;整数成本1,整数成本2
List <Employee> employeeList = new ArrayList<>();
// data population in inputMap
Map<String, Output> outputMap = new HashMap<>();
for (Employee emp : employeeList)
{
Output op = outputMap.get(emp.getName());
if(op == null){
Output newOp = new Output ();
newOp.setCost1(emp.getCost1())
newOp.setCost2(emp.getCost2())
newOp.put(emp.getName(), newOp);
}else{
int cost1 = op.getCost1() + emp.getCost1();
int cost2 = op.getCost2() + emp.getCost2();
op.setCost1(cost1);
op.setCost2(cost2);
newOp.put(emp.getName(), op);
}
}
答案 0 :(得分:4)
我假设您的结构类似:
static class Output {
private final int cost1;
private final int cost2;
public Output(int cost1, int cost2) {
this.cost1 = cost1;
this.cost2 = cost2;
}
@Override
public String toString() {
return "cost1 = " + cost1 + " cost2 = " + cost2;
}
// ... getter
}
static class Employee {
private final String name;
private final int cost1;
private final int cost2;
public Employee(String name, int cost1, int cost2) {
this.name = name;
this.cost1 = cost1;
this.cost2 = cost2;
}
// ...getters
}
然后解决方案将是Employee::getName
的第一个分组,并通过Output
缩小为Collectors.reducing
Map<String, Output> map = Arrays.asList(
new Employee("e", 12, 12),
new Employee("f", 13, 13),
new Employee("e", 11, 11))
.stream()
.collect(Collectors.groupingBy(Employee::getName,
Collectors.reducing(
new Output(0, 0),
emp -> new Output(emp.getCost1(), emp.getCost2()),
(left, right) -> new Output(left.getCost1() + right.getCost1(), left.getCost2() + right.getCost2()))));
System.out.println(map); // {e=cost1 = 23 cost2 = 23, f=cost1 = 13 cost2 = 13}
答案 1 :(得分:3)
每当您需要从流的元素中获取简化地图时,您可以使用Collectors.toMap
的三参数版本:
Map<String, Output> result = employeeList.stream()
.collect(Collectors.toMap(
Employee::getName,
employee -> new Output(employee.getCost1(), employee.getCost2()),
(left, right) -> {
left.setCost1(left.getCost1() + right.getCost1());
left.setCost2(left.getCost2() + right.getCost2());
return left;
}));
Collectors.toMap
,顾名思义,将流的元素收集到地图中。它的第一个参数是一个将流的元素转换为键的函数,第二个参数是另一个将流的元素转换为值的函数,第三个参数是一个合并函数,当键上发生碰撞时应用于值。
在这种情况下,我在合并函数的左操作数上使用可变缩减。这是为了避免创建Output
类的过多实例。减少这种方式是安全的,因为在value函数(Collectors.toMap
的第二个参数)中,我正在创建Output
类的新实例。
如果您可以将以下构造函数和方法添加到Output
类,则可以大大改进此解决方案:
// creates an Output instance out of an Employee instance
public Output(Employee employee) {
this.cost1 = employee.getCost1();
this.cost2 = employee.getCost2();
}
// merges another Output instance into this Output instance
public Output merge(Output another) {
this.cost1 += another.cost1;
this.cost2 += another.cost2;
return this;
}
现在,收集到地图会更简单:
Map<String, Output> result = employeeList.stream()
.collect(Collectors.toMap(Employee::getName, Output::new, Output::merge));