Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 adding values of multiple property of an Object List

Lets say I have a class below with getters and setters but with only default constructor.

Note: I'm not allowed to change the structure of this class.

class Target {

    private String year;
    private String month;
    private String name;
    private double target;
    private double achieved;


    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    public String getMonth() {
        return month;
    }

    public void setMonth(String month) {
        this.month = month;
    }

    public String getName() {
        return name;
    }

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

    public double getTarget() {
        return target;
    }

    public void setTarget(double target) {
        this.target = target;
    }

    public double getAchieved() {
        return achieved;
    }

    public void setAchieved(double achieved) {
        this.achieved = achieved;
    }    
}

I have to add the Target and Achieved columns values based on year and Name.

Year Month Name Target Achieved
2018  8    Joey 50.00   10.00
2018  9    Joey 200.00  100.00
2018  9    Fred 200.00  150.00
2018  9    Fred 20.00   50.00

So the output would be:

Year Month Name Target  Achieved
2018  8    Joey 50.00   10.00
2018  9    Joey 200.00  100.00
2018  9    Fred 220.00  200.00

I've seen an example on how I could achieve something like this if I had a constructor that accepts parameters but I'm not so clear on the concept Group by and sum objects like in SQL with Java lambdas?:

How do I achieve this with just the default constructor to get same type List<Target> but with calculated values of multiple columns?

like image 866
Sujal Avatar asked Sep 23 '18 10:09

Sujal


People also ask

How do you check if a value is present in list of objects in Java?

ArrayList contains() method in Java is used for checking if the specified element exists in the given list or not. Returns: It returns true if the specified element is found in the list else it returns false.

What is the use of PEEK in Java Stream?

This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline. Since Java 9, if the number of elements is known in advance and unchanged in the stream, the . peek () statement will not be executed due to performance optimization.


1 Answers

It seems that you need to group based on three things: Year, Month and Name, so this could look like this:

Collection<Target> merged = yourListOfTargets
            .stream()
            .collect(Collectors.toMap(
                    t -> List.of(t.getYear(), t.getMonth(), t.getName()),
                    Function.identity(),
                    (left, right) -> {
                        left.setTarget(left.getTarget() + right.getTarget());
                        left.setAchieved(left.getAchieved() + right.getAchieved());
                        return left;
                    }))
            .values();

As Federico mentions in comments, this will alter your elements in the initial List. You might be OK with it, but if you are not, you need to replace Function.identity() with a copying Function that would create a new Target from an existing one.

like image 83
Eugene Avatar answered Oct 18 '22 17:10

Eugene