设置具有特定值的下一个项目列表中的项目值

时间:2017-11-09 11:17:54

标签: java java-8

我有一个SalesOrders列表,包括Inactive和Active。我想遍历整个列表并设置每个SalesOrder处于活动状态的时间长度。 (该列表已由StartTime排序)

我的循环如下:

for(int i = 0; i < salesOrders.size(); i++) {
    if(salesOrders.get(i).getStatus() == RecordStatus.ACTIVE) {
        ELDDutyLog activeSalesOrder = salesOrders.get(i);

        for(int j = i + 1; j < salesOrders.size(); j++) {
            if(salesOrders.get(j).getStatus() == RecordStatus.ACTIVE) {
                ELDDutyLog nextActiveSalesOrder = salesOrders.get(j);

                salesOrders.get(i).setActiveDurationMinutes(
                    Minutes.minutesBetween(
                        activeSalesOrder.getStartTime(),
                        nextActiveSalesOrder.getStartTime()
                    ).getMinutes()
                );
                break;
            }
        }
    }
}
return salesOrders;

虽然这种方法有效,但我觉得必须有更好的方法来实现这一点,可能是使用Java 8?任何人都可以向我提出任何方向吗?

3 个答案:

答案 0 :(得分:4)

每次跳过不活跃的销售订单时,您不必再次循环整个列表。相反,您可以过滤活动销售订单一次,然后您始终知道下一个活动销售订单是已过滤列表中的下一个订单。

像这样(未经测试):

List<ELDDutyLog> activeSalesOrders = salesOrders.stream()
        .filter(so -> so.getStatus() == RecordStatus.ACTIVE)
        .collect(Collectors.toList());

for (int i = 0; i < activeSalesOrders.size() - 1; i++) {
    activeSalesOrders.get(i).setActiveDurationMinutes(
                    Minutes.minutesBetween(
                        activeSalesOrders.get(i).getStartTime(),
                        activeSalesOrders.get(i+1).getStartTime()
                    ).getMinutes()
                );
}

答案 1 :(得分:3)

我希望我理解正确。尝试(未测试):

salesOrders.stream()
  .filter(salesOrder -> salesOrder.getStatus() == RecordStatus.ACTIVE)
  .reduce((current, next) -> {
    current.setActiveDurationMinutes(
      Minutes.minutesBetween(
        current.getStartTime(),
        next.getStartTime()
      ).getMinutes()
    );
    return next;
  });

说实话......对于reduce来说这有点奇怪,但我认为它会起作用。

答案 2 :(得分:1)

无需嵌套两个循环;您搜索的nextActiveSalesOrder计算setActiveDurationMinutes调用的参数,与您在外循环的下一次迭代中搜索的activeSalesOrder相同。除此之外,尽管您已将该值存储在salesOrders.get(i)中,但您在内部操作中不必要地调用activeSalesOrder

ELDDutyLog activeSalesOrder = null;
for(ELDDutyLog nextActiveSalesOrder: salesOrders) {
    if(nextActiveSalesOrder.getStatus() != RecordStatus.ACTIVE) continue;
    if(activeSalesOrder != null)
        activeSalesOrder.setActiveDurationMinutes(
            Minutes.minutesBetween(
                activeSalesOrder.getStartTime(),
                nextActiveSalesOrder.getStartTime()
            ).getMinutes()
        );
    activeSalesOrder = nextActiveSalesOrder;
}

除此之外......什么样的API要求你写Minutes.minutesBetween(a, b).getMinutes()之类的东西? API需要被告知您需要多少次分钟? 与java.time比较:

  1. ChronoUnit.MINUTES.between(a, b)(已返回long)或
  2. a.until(b, ChronoUnit.MINUTES)(dito,仍然没有冗余)