Java 8 group by sum condition

I have an officer officer

public class Officer {

    private String name;
    private int totalDaysInOffice;

    public Officer(String name, int totalDaysInOffice) {
        this.name = name;
        this.totalDaysInOffice = totalDaysInOffice;
    }

    @Override
    public String toString() {
        return "Officer{" +
                "name='" + name + '\'' +
                ", totalDaysInOffice=" + totalDaysInOffice +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getTotalDaysInOffice() {
        return totalDaysInOffice;
    }

    public void setTotalDaysInOffice(int totalDaysInOffice) {
        this.totalDaysInOffice = totalDaysInOffice;
    }
}

Here, each officer spent days in the office (just composed by a variable).

What I want to do is to split the officers as soon as I have the sum of 10,000 days in a separate list

According to the example below, I want to have a list with

one list with John , Matthew , and Robert since they sum to more 10K 
One list with Patrick as he has 10K 
Dave would be in separate list.

I tried a group, but not sure how to add this condition.

public class OffierExample {

    public static void main(String[] args) {

        List<Officer> officerList = new ArrayList<>();

        officerList.add(new Officer("John",5000));
        officerList.add(new Officer("Matthew",3000));
        officerList.add(new Officer("Robert",2000));
        officerList.add(new Officer("Dave",2000));
        officerList.add(new Officer("Patrick",10000));

        Map<Officer, Integer> collect = officerList.stream().collect(Collectors.groupingBy(o -> o, Collectors.summingInt(Officer::getTotalDaysInOffice)));
        System.out.println(collect);
    }
}

Anyway, this can be done in Java 8.

**

***** ***** UPDATE

**

I used a traditional loop, but I want to use a Java 8 group if possible

public class OffierExample {

    public static void main(String[] args) {

        List<Officer> officerList = new ArrayList<>();

        officerList.add(new Officer("John", 5000));
        officerList.add(new Officer("Matthew", 3000));
        officerList.add(new Officer("Robert", 2000));
        officerList.add(new Officer("Dave", 2000));
        officerList.add(new Officer("Patrick", 10000));

        officerList.add(new Officer("YYYY", 600));
        officerList.add(new Officer("XXXX", 600));

        //keep totalDaysInOfficeSum
        int totalDaysInOfficeSum = 0;

        //the final list
        List<List<Officer>> off = Lists.newArrayList();

        //the working list
        List<Officer> tempOffList = Lists.newArrayList();

        for (Officer officer : officerList) {

            //get sum
            totalDaysInOfficeSum = totalDaysInOfficeSum + officer.getTotalDaysInOffice();

            //if sum is more than 10K or equal
            if (totalDaysInOfficeSum >= 10000) {

                //add it in temp list
                tempOffList.add(officer);

                //add in master list
                off.add(tempOffList);

                //reset temp list
                tempOffList = new ArrayList<>();

                //reset sum
                totalDaysInOfficeSum = 0;
                continue;

            }

            //add in temp list
            tempOffList.add(officer);


        }

        //any left over
        if (!tempOffList.isEmpty()) {
            off.add(tempOffList);
        }

        //printint out
        System.out.println("Officers list =" + off.size());

        off.forEach(o -> {

            System.out.println("List size:" + o.size());
            o.forEach(oo -> {
                System.out.println(oo.getName() + "::" + oo.getTotalDaysInOffice());
            });
            System.out.println("====================");
        });
    }
}

Output

Officers list =3
List size:3
John::5000
Matthew::3000
Robert::2000
====================
List size:2
Dave::2000
Patrick::10000
====================
List size:2
YYYY::600
XXXX::600
====================
+4
source share
2 answers

Something like that:

List<List<Officer>> result = officerList.stream().collect(Collector.of(
            () -> new ArrayList<List<Officer>>(),
            (list, entry) -> {
                if (list.size() == 0) {
                    List<Officer> inner = new ArrayList<>();
                    inner.add(entry);
                    list.add(inner);
                } else {
                    List<Officer> last = list.get(list.size() - 1);
                    int sum = last.stream().mapToInt(Officer::getTotalDaysInOffice).sum();
                    if (sum < 10_000) {
                        last.add(entry);
                    } else {
                        List<Officer> inner = new ArrayList<>();
                        inner.add(entry);
                        list.add(inner);
                    }
                }
            },
            (left, right) -> {
                throw new IllegalArgumentException("Not for parallel");
            }));
+2
source

Here is a solution from my library :

MutableInt sum = MutableInt.of(0);
List<List<Officer>> off = Stream.of(officerList)
        .splitToList(officer -> sum.getAndSet(sum.value() < 10000 ? sum.value() + officer.getTotalDaysInOffice() : 0) < 10000)
        .toList();

Or:

List<List<Officer>> off = Seq.of(officerList)
        .split(officer -> sum.getAndSet(sum.value() < 10000 ? sum.value() + officer.getTotalDaysInOffice() : 0) < 10000);
0
source

Source: https://habr.com/ru/post/1688629/


All Articles