Java 8 - 如何通过 groupingBy 和 summingInt 使用 lambda 并使用按位运算符

标签 java lambda java-8 java-stream collectors

我有自己的类 CheckIn,属性 dayStringworkingHoursint inProgressboolean:

public class CheckIn {
    public int id;
    public String day;
    public int workingHours;
    public boolean inProgress;

    public CheckIn(String day, in hours, boolean inProgress) {
        this.day = day;
        this.workingHours = hours;
        this.inProgress = inProgress;
    }
}

我的系统中有条目列表,我需要这些条目的摘要并将它们按天分组并对工作时间求和。在这里没问题,我可以使用 lambda 来实现它,但是如果我想设置进度为真,如果有任何条目为真怎么办?

// Suppose this is the inputs 
List<CheckIn> checkinsList = new ArrayList<>();
checkinsList.add(new CheckIn("26-11-2015",6,true));
checkinsList.add(new CheckIn("27-11-2015",6,false));
checkinsList.add(new CheckIn("26-11-2015",6,false));
checkinsList.add(new CheckIn("27-11-2015",4,false));
checkinsList.add(new CheckIn("26-11-2015",1,false));
checkinsList.add(new CheckIn("28-11-2015",6,false));
checkinsList.add(new CheckIn("28-11-2015",6,false));
checkinsList.add(new CheckIn("28-11-2015",6,true));


List<CheckIn> summary = new ArrayList<>();

checkinsList.stream().collect(Collectors.groupingBy(Function.identity(),
    () -> new TreeMap<>(
        Comparator.<CheckIn, String>comparing(entry -> entry.day)),
        Collectors.summingInt(entry -> entry.duration))).forEach((e, sumTargetDuration) -> {
        CheckIn entry = new CheckIn();
        entry.day = e.day;
        entry.duration = sumTargetDuration;
        // Here my something like what I need?
        entry.inProgress = e.inProgress;
        summary.add(entry);
});

我需要 summary 列表包含(在本例中用于输入)在这 3 天中有 3 个项目:

我想要这样的结果:

  • 第一项 "26-11-2015", 13 , true <-- true 因为天 "26-11-2015"有一项为 true .
  • 第二项 "27-11-2015", 10 , false
  • 第三项 "28-11-2015", 18 , true

我希望摘要带有 inProgress true 如果那天有任何条目 inProgress == true 它适用于 lambda 吗?

最佳答案

您需要为此任务构建自定义收集器。问题是没有内置的收集器可以将多个收集器组合在一起并应用整理操作。在这种情况下,我们需要组合 3 个收集器:summingIntreducing,这将每个inProgressmapping,它将映射到当天。

下面的类将在收集过程中保存摘要并相应地计算结果。我们可以添加关于当天的额外检查,因为它在整个过程中应该是相同的,但为了简单起见,我省略了这些。

public class CheckInSummary {

    private int workingHours;
    private boolean inProgress;
    private String day;

    public void accept(CheckIn checkIn) {
        workingHours += checkIn.workingHours;
        inProgress = inProgress || checkIn.inProgress;
        day = checkIn.day;
    }

    public CheckInSummary combine(CheckInSummary summary) {
        workingHours += summary.workingHours;
        inProgress = inProgress || summary.inProgress;
        return this;
    }

    public CheckIn finish() {
        return new CheckIn(day, workingHours, inProgress);
    }

}

然后,您可以使用以下方法从此类创建一个收集器:

private static Collector<CheckIn, ?, CheckIn> summary() {
    return Collector.of(
                CheckInSummary::new,
                CheckInSummary::accept,
                CheckInSummary::combine,
                CheckInSummary::finish
           );
}

你终于可以像这样使用它了:

List<CheckIn> result = 
      new ArrayList<>(checkinsList.stream()
                                  .collect(groupingBy(c -> c.day, summary()))
                                  .values());

测试用例的输出:

[[27-11-2015, 10, false], [26-11-2015, 13, true], [28-11-2015, 18, true]]

这个列表没有排序,但如果你想排序,你只需要额外调用 sort() 比较日期。

关于Java 8 - 如何通过 groupingBy 和 summingInt 使用 lambda 并使用按位运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33941963/

相关文章:

java - 一起使用 PartioningBy 和 groupingBy 时无法获得所需的输出

java - 如何使用 Java8 流将列表列表转换为单个列表

java - 如何使用 Java 驱动程序获取 MongoDB 中嵌入文档数组的特定值

java - 检测字符串中 n-grams 的更快方法?

c++ - 数组的 Lambda 捕获(按值)只是复制指针?

glass-fish 服务器的 java 8 lambda 表达式支持

Instant.EPOCH 的 Java 8 时区不正确

java - 创建 bean 时出错 - maven spring hibernate 项目

java.lang.NullPointerException : Attempt to read from field 'long org.opencv.core.Mat.nativeObj' on a null object reference

c# - Lambda 表达式中带有 AND 运算符的 Lambda 表达式