简体   繁体   中英

Java 8 - how to work with lambda with groupingBy and summingInt and use Bitwise operator

I have my own class called CheckIn with attributes day as String , workingHours as int and inProgress as boolean :

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;
    }
}

And I have list of entries in my system, and I need summary of those entries and group them with days and sum the workingHours. It's Ok here and I'm able to it with lambda, but what if then I want to set is progress to true if there is any in entries is true?

// 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);
});

I need the summary List contains (in this case for input) have 3 items for those 3 days with :

Result that I want like this :

  • First item "26-11-2015" , 13 , true <-- true because there is 1 item for day "26-11-2015" have true.
  • Second item "27-11-2015" , 10 , false
  • Third item "28-11-2015" , 18 , true

I want the summary come with inProgress true if there is any of entries in that day have inProgress == true is it applicable with lambda?

You need to build a custom Collector for this task. The problem is that there is no built-in collector that will combine multiple collectors together and apply a finishing operation. In this case, we would need to combine 3 collectors: summingInt , reducing , which would or s each inProgress , and mapping , which would map to the day.

The following class will hold the summary during the collection process and calculates the result accordingly. We could add extra-checks regarding the day because it should be the same during the whole process, but I left those out for simplicity.

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);
    }

}

Then, you can create a Collector from this class using:

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

and you can finally use it like this:

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

Output from your test case:

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

This list is not sorted but if you want to sort it, you just need an additional call to sort() comparing the day.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM