【问题标题】:Mapping, aggregating and composing totals using Java 8 Streams使用 Java 8 Streams 映射、聚合和组合总计
【发布时间】:2019-10-03 20:06:12
【问题描述】:

我正在尝试重新创建一个进程来创建一个对象列表,这些对象列表是使用 Java 8 流的另一个对象列表的聚合。

例如,我有一个类,如下所述,它是通过数据库调用或类似方法提供的

public class Order {

    private String orderNumber;        
    private String customerNumber;
    private String customerGroup;
    private Date deliveryDate;
    private double orderValue;
    private double orderQty;
}

在我的应用程序的其他地方,我有一个 OrderTotal 类,它表示和聚合按客户编号和组进行的订单分组,并对 orderValue 和 orderQty 的总数求和。 (在 customerGroup 和 customerNumber 上使用 equals 和 hashcode)

public class OrderTotal {

    private String customerGroup;
    private String customerNumber;
    private double totalValue;
    private double totalQty;
}

我们在 java 8 之前实现这一点的“长手”方式如下

public Collection<OrderTotal> getTotals(List<Order> orders) {
    ///map created for quick access to the order total for each order 
    Map<OrderTotal, OrderTotal> map = new HashMap<>();
    ///loop through all orders adding to the relevaent order total per iteration
    for (Order order : orders) {
        OrderTotal orderTotal = createFromOrder(order);
        {
            ///if the order total already exists in the map use that one, otherwise add it to the map.
            OrderTotal temp = map.get(orderTotal);
            if(temp == null){
                map.put(orderTotal, orderTotal);
            }else{
                orderTotal = temp;
            }
        }
        ///add the values to the total 
        aggregate(orderTotal, order);
    }        
    return map.values();
}

private OrderTotal createFromOrder(Order order) {
    OrderTotal orderTotal = new OrderTotal();
    orderTotal.setCustomerGroup(order.getCustomerGroup());
    orderTotal.setCustomerNumber(order.getCustomerNumber());
    return orderTotal;
}

private void aggregate(OrderTotal orderTotal, Order order){
    orderTotal.setTotalQty(orderTotal.getTotalQty() + order.getOrderQty());
    orderTotal.setTotalValue(orderTotal.getTotalValue() + order.getOrderValue());
}

我一直在研究使用分组依据和归约函数的收集器,但它们似乎都专注于聚合订单类,而不是在 OrderTotal 类中组合总计。

我正在寻找一个整洁的流或收集功能,以消除此代码中的所有臃肿。

【问题讨论】:

  • 您正在寻找的是来自 Orders 的总和 totalValuetotalQty 并将它们放入 OrderTotal - 这对于两个流来说相当简单
  • 可能非常适合Code Review,但请务必在发布之前先阅读他们的help center,以确保它符合主题

标签: java java-8 java-stream aggregation composition


【解决方案1】:

你可以这样做 -

Double totalQtyAgg =  orders.stream()
                            .map(x -> createFromOrder(x))
                            .mapToDouble(x -> x.totalQty)
                            .sum();
Double totalValueAgg = orders.stream()
                             .map(x -> createFromOrder(x))
                             .mapToDouble(x -> x.totalValue)
                             .sum();

【讨论】:

  • 您好,感谢您的回复。这将为我提供所有订单的总数,但我正在寻找每个 customerGroup 和 customerNumber 组合的总数
【解决方案2】:

您可以按如下方式使用toMap 收集器:

Collection<OrderTotal> result = orders.stream()
            .map(o -> createFromOrder(o))
            .collect(toMap(Function.identity(),
                        Function.identity(),
                        (l, r) -> {
                            aggregate(l, r);
                            return l;
                        }))
                .values();

请注意,这需要将 aggregate 方法参数更改为 aggregate(OrderTotal orderTotal, OrderTotal order){ ... },即两个参数的类型均为 OrderTotal

或者您可以完全删除aggregate 方法并执行toMap 中的逻辑:

Collection<OrderTotal> result = orders.stream()
            .map(o -> createFromOrder(o))
            .collect(toMap(Function.identity(),
                    Function.identity(),
                    (l, r) -> {
                        l.setTotalQty(l.getTotalQty() + r.getTotalQty());
                        l.setTotalValue(l.getTotalValue() + r.getTotalValue());
                        return l;
                    }))
            .values();

【讨论】:

  • 冒昧地编辑了第二个,是的,1+,欢迎回来
  • 实际上,我认为 OP 可能希望按 function.identity 分组。顺便说一句,感谢您的编辑。
  • 次要注意hashCode 有点不同,尽管customeName 对我来说非常独特......
  • 小心 OP 说 OrderTotaloverrides equals/hashCode,not Order
  • 很好的答案,非常感谢。我唯一的额外步骤是修改 createFromOrder 方法以从订单中设置 totalQty 和 totalValue 的值。
猜你喜欢
  • 2019-02-10
  • 2015-10-31
  • 2012-03-08
  • 2017-08-15
  • 1970-01-01
  • 2021-10-12
  • 2018-12-22
  • 1970-01-01
  • 2016-06-10
相关资源
最近更新 更多