当前的方法基于双倍类型的产品奖励。
public Map<String, BigDecimal> averageProductPriceInCategory() {
return shopping.entrySet()
.stream()
.flatMap(e -> e.getValue().keySet().stream())
.collect(Collectors.groupingBy(Product::getCategory,
Collectors.averagingDouble(Product::getPrize)));
}
购物基本上是一张 map :Map<Client, Map<Product,Integer>>
,
- 外键代表客户端
- 内部 key 代表产品。产品类成员是名称、类别、价格(以前为 double 类型) - 希望将提供的代码重构为使用价格作为 BigDecimal 类型的代码
- 内部映射值(整数)代表属于特定客户的指定产品的数量
以下代码片段只能用于计算属于指定类别的产品的总奖金。不确定如何使用 BigDecimals 计算类别的平均产品奖
Map<String, BigDecimal> totalProductPriceInEachCategory = shopping.entrySet().stream()
.flatMap(e -> e.getValue().keySet().stream())
.collect(Collectors.groupingBy(Product::getCategory,
Collectors.mapping(Product::getPrize,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
最佳答案
看看如何 Collectors.averagingDouble
或 Collectors.averagingInt
已实现。
public static <T> Collector<T, ?, Double>
averagingInt(ToIntFunction<? super T> mapper) {
return new CollectorImpl<>(
() -> new long[2],
(a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
}
本质上,您需要一个可变的累积类型来保存 BigDecimal
这是产品价格的总和,以及 int
这是经过加工的一些产品。有了这个,问题就归结为编写一个简单的 Collector<Product, AccumulationType, BigDecimal>
.
我简化了一个示例并删除了 getter/setter 和全参数构造函数。而不是嵌套类 ProductPriceSummary
,您可以对 2 个元素使用任何可变持有者类。
class AverageProductPriceCollector implements Collector<Product, AverageProductPriceCollector.ProductPriceSummary, BigDecimal> {
static class ProductPriceSummary {
private BigDecimal sum = BigDecimal.ZERO;
private int n;
}
@Override
public Supplier<ProductPriceSummary> supplier() {
return ProductPriceSummary::new;
}
@Override
public BiConsumer<ProductPriceSummary, Product> accumulator() {
return (a, p) -> {
// if getPrize() still returns double
// a.sum = a.sum.add(BigDecimal.valueOf(p.getPrize()));
a.sum = a.sum.add(p.getPrize());
a.n += 1;
};
}
@Override
public BinaryOperator<ProductPriceSummary> combiner() {
return (a, b) -> {
ProductPriceSummary s = new ProductPriceSummary();
s.sum = a.sum.add(b.sum);
s.n = a.n + b.n;
return s;
};
}
@Override
public Function<ProductPriceSummary, BigDecimal> finisher() {
return s -> s.n == 0 ?
BigDecimal.ZERO :
s.sum.divide(BigDecimal.valueOf(s.n), RoundingMode.CEILING);
}
@Override
public Set<Characteristics> characteristics() {
return Collections.emptySet();
}
}
关于java - 使用 Streams API 收集器平均 BigDecimals,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54278847/