6

In Java 8 group by how to groupby on a single field which returns more than one field. In the below code by I am passing name and the field to be summed which is 'total' in this scenario. however I would like to return sum of 'total' and 'balance' field for every 'name' in the Customer list (can be a map with key and value as array). Can it be done by using a single groupingBy with the return values?

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class Sample {

    public static void main(String str[]){
        Customer custa = new Customer("A",1000,1500);
        Customer custa1 = new Customer("A",2000,2500);
        Customer custb = new Customer("B",3000,3500);
        Customer custc = new Customer("C",4000,4500);
        Customer custa2 = new Customer("A",1500,2500);

        List<Customer> listCust = new ArrayList<>();
        listCust.add(custa);
        listCust.add(custa1);
        listCust.add(custb);
        listCust.add(custc);
        listCust.add(custa2);

        Map<String, Double> retObj = 
            listCust.stream().collect(Collectors.groupingBy(Customer::getName,Collectors.summingDouble(Customer::getTotal)));


    System.out.println(retObj);
    }

    private static class Customer {
        private String name;
        private double total;
        private double balance;

        public Customer(String name, double total, double balance) {
            super();
            this.name = name;
            this.total = total;
            this.balance = balance;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public double getTotal() {
            return total;
        }
        public void setTotal(double total) {
            this.total = total;
        }
        public double getBalance() {
            return balance;
        }
        public void setBalance(double balance) {
            this.balance = balance;
        }
        @Override
        public String toString() {
            return "Customer [name=" + name + ", total=" + total + ", balance=" + balance + "]";
        }

    }
}

Expected Output -

{ 
  A = [4500,6500],
  B = [3000,3500] ,
  C = [4000,4500]
}

2 Answers 2

6

You can write your own collector to sum total and balance

Collector<Customer, List<Double>, List<Double>> collector = Collector.of(
        () -> Arrays.asList(0.0, 0.0),
        (a, t) -> {
            a.set(0, a.get(0) + t.getTotal());
            a.set(1, a.get(1) + t.getBalance());
        },
        (a, b) -> {
            a.set(0, a.get(0) + b.get(0));
            a.set(1, a.get(1) + b.get(1));
            return a;
        }
);

Map<String, List<Double>> retObj = listCust
        .stream()
        .collect(Collectors.groupingBy(Customer::getName, collector));

System.out.println(retObj);

result

{A=[4500.0, 6500.0], B=[3000.0, 3500.0], C=[4000.0, 4500.0]}
Sign up to request clarification or add additional context in comments.

Comments

3

You can also use the toMap collector to accomplish the task at hand.

Map<String, List<Double>> retObj =
        listCust.stream()
                .collect(Collectors.toMap(Customer::getName,
                c -> new ArrayList<>(Arrays.asList(c.getTotal(), c.getBalance())),
                (l, l1) -> {
                    l.set(0, l.get(0) + l1.get(0));
                    l.set(1, l.get(1) + l1.get(1));
                    return l;
                }));

2 Comments

You don't need to wrap the Arrays.asList(...) in a new ArrayList<>(...) since Arrays.asList is a fixed-size list that supports replacing of its values
@FedericoPeraltaSchaffner true, but the main purpose I passed it into the ArrayList constructor is for whatever reason the OP wants to modify the list in terms or removing, adding etc...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.