4

I have an object 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 have spent days in office(just made up variable).

What I want to do is the divide the officers once I have the sum of days 10000 in separate list

Based on example below , I want to have 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 have tried group by but not sure how can I 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);
    }
}

Is there anyways it can be done in Java 8

**

*****UPDATE*****

**

I have achieved using traditional loop but I want to use Java 8 group by 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
====================
Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Makky
  • 17,117
  • 17
  • 63
  • 86

3 Answers3

2

Something like this:

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");
            }));
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • Thanks. I will stick to traditional way but will accept this as answer too – Makky Nov 02 '17 at 20:23
  • 1
    You know, there’s no specification saying that a combiner can’t be used in a sequential execution. The simplest combiner implementation is to iterate over all `Officer` instances contained in `right` and accumulate them to `left`. This requires to store the accumulator function into a local variable to use it at two places… – Holger Nov 03 '17 at 07:50
  • @Holger yeah I do know that... I admit I was just too lazy doing it yesterday – Eugene Nov 03 '17 at 07:59
0

Here is the solution with 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);
123-xyz
  • 619
  • 4
  • 5
0

Java 8 way

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

List<List<Officer>> separatedOfficerLists = officerList.stream()
        .sorted(Comparator.comparing(Officer::getTotalDaysInOffice).reversed())
        .collect(Collectors.groupingByConcurrent(o -> {
            int totalDays = o.getTotalDaysInOffice();
            int divisor = (totalDays / 10000) + 1;
            return (divisor * 10000) - totalDays;
        })).entrySet().stream()
        .sorted(Map.Entry.comparingByKey())
        .map(Map.Entry::getValue)
        .collect(Collectors.toList());

System.out.println(separatedOfficerLists);
Makky
  • 17,117
  • 17
  • 63
  • 86