【问题标题】:Java 8 - how to work with lambda with groupingBy and summingInt and use Bitwise operatorJava 8 - 如何使用带有 groupingBy 和 summingInt 的 lambda 并使用按位运算符
【发布时间】:2015-11-26 15:16:11
【问题描述】:

我有自己的班级CheckIn,其属性dayStringworkingHoursintinProgressboolean

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 来实现,但是如果有任何 in 条目为真,那么我想将进度设置为真怎么办?

// 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 因为有 1 天“26-11-2015”的项目为真。
  • 第二条"27-11-2015" , 10 , false
  • 第三条"28-11-2015" , 18 , true

如果当天有任何条目有inProgress == true,我希望摘要带有inProgress true 是否适用于lambda?

【问题讨论】:

    标签: java lambda java-8 java-stream collectors


    【解决方案1】:

    您需要为此任务构建自定义收集器。问题是没有内置的收集器可以将多个收集器组合在一起并应用整理操作。在这种情况下,我们需要合并 3 个收集器:summingIntreducing,它们将 ors 每个 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() 比较日期即可。

    【讨论】:

    • 非常感谢,我会在再次打开我的 IDE 时尝试此操作,如果有效则获取答案。
    • 嗨,我从假期回来,并尝试了解决方案,非常感谢您。稍作修改,我使用了Collectors.groupingBy 并从收集器方法中删除了static
    猜你喜欢
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 2016-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-23
    • 2018-02-04
    相关资源
    最近更新 更多