Collectors.reducing 的正确语法
Correct syntax for Collectors.reducing
我有一个 Order class 和一个 LineItem class 如下所示:
@AllArgsConstructor
@Getter
@ToString
static class Order {
long orderId;
List<LineItem> lineItems;
}
@AllArgsConstructor
@Getter
@ToString
static class LineItem {
String name;
BigDecimal price;
}
和一个订单列表,我想从中获取一个映射 Map<String,BigDecimal> totalByItem
,其中键是 LineItem 的名称,值是列表中所有订单的总价。为此,我想将 Collectors.groupingBy 与 Collectors.reducing 结合使用,但努力使用正确的语法。有人可以帮忙吗?
List<Order> orders = List.of(new Order(1L, List.of(new LineItem("Item-A", BigDecimal.valueOf(1)),
new LineItem("Item-B", BigDecimal.valueOf(2)),
new LineItem("Item-C", BigDecimal.valueOf(3)))),
new Order(2L, List.of(new LineItem("Item-A", BigDecimal.valueOf(1)),
new LineItem("Item-D", BigDecimal.valueOf(4)),
new LineItem("Item-E", BigDecimal.valueOf(5)))),
new Order(3L, List.of(new LineItem("Item-B", BigDecimal.valueOf(2)),
new LineItem("Item-C", BigDecimal.valueOf(3)),
new LineItem("Item-D", BigDecimal.valueOf(4)))));
现在有的地方放什么????
Map<String,BigDecimal> totalByItem =
orders.stream()
.flatMap(order -> order.getLineItems().stream())
.collect(Collectors.groupingBy(LineItem::getName,
lineItem -> Collectors.reducing(BigDecimal.ZERO,(a,b) -> ???)));
你几乎完美了。您需要调用映射以从 LineItem 中提取价格。然后就可以做下图的归约操作了
Map<String, BigDecimal> totalByItem = orders.stream()
.flatMap(order -> order.getLineItems().stream())
.collect(Collectors.groupingBy(LineItem::getName,
Collectors.mapping(LineItem::getPrice,
Collectors.reducing(
BigDecimal.ZERO, BigDecimal::add))));
请注意,您可以按如下方式完成归约操作:
Collectors.reducing(BigDecimal.ZERO, (a,b)->a.add(b)))));
根据您当前的数据,打印出以下内容
totalByItem.entrySet().forEach(System.out::println);
Item-A=2
Item-E=5
Item-D=8
Item-C=6
Item-B=4
groupingBy
将 Collector
作为其第二个参数,因此您不应传递 lambda lineItem -> ...
,而应直接传递 Collector.reducing(...)
。
此外,由于您正在将一堆 LineItem
减少为一个 BigDecimal
,您应该使用 reducing
的 three-parameter overload,以及 mapper
public static <T, U> Collector<T,?,U> reducing(
U identity,
Function<? super T,? extends U> mapper,
BinaryOperator<U> op)
mapper
是您指定如何将 LineItem
变成 BigDecimal
的地方。您可能将其与 groupingBy
.
的第二个参数混淆
总结一下:
Map<String,BigDecimal> totalByItem =
orders.stream()
.flatMap(order -> order.getLineItems().stream())
.collect(
Collectors.groupingBy(
LineItem::getName,
Collectors.reducing(
BigDecimal.ZERO,
LineItem::getPrice, // <----
BigDecimal::add
)
)
);
正如 Holger 评论的那样,整个 groupingBy
收集器也可以替换为 toMap
收集器,根本不用 reducing
。
.collect(
Collectors.toMap(
LineItem::getName, // key of the map
LineItem::getPrice, // value of the map
BigDecimal::add // what to do with the values when the keys duplicate
)
);
我有一个 Order class 和一个 LineItem class 如下所示:
@AllArgsConstructor
@Getter
@ToString
static class Order {
long orderId;
List<LineItem> lineItems;
}
@AllArgsConstructor
@Getter
@ToString
static class LineItem {
String name;
BigDecimal price;
}
和一个订单列表,我想从中获取一个映射 Map<String,BigDecimal> totalByItem
,其中键是 LineItem 的名称,值是列表中所有订单的总价。为此,我想将 Collectors.groupingBy 与 Collectors.reducing 结合使用,但努力使用正确的语法。有人可以帮忙吗?
List<Order> orders = List.of(new Order(1L, List.of(new LineItem("Item-A", BigDecimal.valueOf(1)),
new LineItem("Item-B", BigDecimal.valueOf(2)),
new LineItem("Item-C", BigDecimal.valueOf(3)))),
new Order(2L, List.of(new LineItem("Item-A", BigDecimal.valueOf(1)),
new LineItem("Item-D", BigDecimal.valueOf(4)),
new LineItem("Item-E", BigDecimal.valueOf(5)))),
new Order(3L, List.of(new LineItem("Item-B", BigDecimal.valueOf(2)),
new LineItem("Item-C", BigDecimal.valueOf(3)),
new LineItem("Item-D", BigDecimal.valueOf(4)))));
现在有的地方放什么????
Map<String,BigDecimal> totalByItem =
orders.stream()
.flatMap(order -> order.getLineItems().stream())
.collect(Collectors.groupingBy(LineItem::getName,
lineItem -> Collectors.reducing(BigDecimal.ZERO,(a,b) -> ???)));
你几乎完美了。您需要调用映射以从 LineItem 中提取价格。然后就可以做下图的归约操作了
Map<String, BigDecimal> totalByItem = orders.stream()
.flatMap(order -> order.getLineItems().stream())
.collect(Collectors.groupingBy(LineItem::getName,
Collectors.mapping(LineItem::getPrice,
Collectors.reducing(
BigDecimal.ZERO, BigDecimal::add))));
请注意,您可以按如下方式完成归约操作:
Collectors.reducing(BigDecimal.ZERO, (a,b)->a.add(b)))));
根据您当前的数据,打印出以下内容
totalByItem.entrySet().forEach(System.out::println);
Item-A=2
Item-E=5
Item-D=8
Item-C=6
Item-B=4
groupingBy
将 Collector
作为其第二个参数,因此您不应传递 lambda lineItem -> ...
,而应直接传递 Collector.reducing(...)
。
此外,由于您正在将一堆 LineItem
减少为一个 BigDecimal
,您应该使用 reducing
的 three-parameter overload,以及 mapper
public static <T, U> Collector<T,?,U> reducing(
U identity,
Function<? super T,? extends U> mapper,
BinaryOperator<U> op)
mapper
是您指定如何将 LineItem
变成 BigDecimal
的地方。您可能将其与 groupingBy
.
总结一下:
Map<String,BigDecimal> totalByItem =
orders.stream()
.flatMap(order -> order.getLineItems().stream())
.collect(
Collectors.groupingBy(
LineItem::getName,
Collectors.reducing(
BigDecimal.ZERO,
LineItem::getPrice, // <----
BigDecimal::add
)
)
);
正如 Holger 评论的那样,整个 groupingBy
收集器也可以替换为 toMap
收集器,根本不用 reducing
。
.collect(
Collectors.toMap(
LineItem::getName, // key of the map
LineItem::getPrice, // value of the map
BigDecimal::add // what to do with the values when the keys duplicate
)
);