Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

417
Views
Java Stream group by 02 fields and aggregate by sum on 2 BigDecimal fields

Need help for a case on Stream with groupingBy I would like to be able to group by 2 different fields and have the sum of other BigDecimal fields, according to the different groupings. Here is my entity :

    public class Customer {
        private String name;
        private String type;
        private BigDecimal total;
        private BigDecimal balance;

// Setter, getter

}

Let's suppose I have as input this list:

Customer custa = new Customer("A", "STANDARD", new BigDecimal("1000"), new BigDecimal("1500"));
    Customer custa1 = new Customer("A", "VIP", new BigDecimal("2000"), new BigDecimal("2500"));
    Customer custb = new Customer("B", "STANDARD", new BigDecimal("3000"), new BigDecimal("3500"));
    Customer custc = new Customer("C", "STANDARD", new BigDecimal("4000"), new BigDecimal("4500"));
    Customer custa2 = new Customer("A", "VIP", new BigDecimal("1500"), new BigDecimal("2500"));
    List<Customer> listCust = new ArrayList<>();
    listCust.add(custa);
    listCust.add(custa1);
    listCust.add(custb);
    listCust.add(custc);
    listCust.add(custa2);

The result should be

[
    {"A", "STANDARD", new BigDecimal("1000"), new BigDecimal("1500")},
    {"A", "VIP", new BigDecimal("3500"), new BigDecimal("5000")},
    {"B", "STANDARD", new BigDecimal("3000"), new BigDecimal("3500")},
    {"C", "STANDARD", new BigDecimal("4000"), new BigDecimal("4500")}
]

I have a beginning of solution, below, but I block at the moment of adding a second aggregation to sum up the balance:

listCust.stream()
                .collect(Collectors.groupingBy(Customer::getName
                    , Collectors.groupingBy(Customer::getType
                        , Collectors.reducing(BigDecimal.ZERO,Customer::getTotal,BigDecimal::add)))
                )
                .entrySet()
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Collection<Customer> customers = listCust.stream()
                                         .collect(Collectors.toMap(
                                                 customer -> customer.getName() + '-' + customer.getType(),
                                                 Function.identity(), (one, two) -> {
                                                     String name = one.getName();
                                                     String type = one.getType();
                                                     BigDecimal total = one.getTotal().add(two.getTotal());
                                                     BigDecimal balance = one.getBalance().add(two.getBalance());
                                                     return new Customer(name, type, total, balance);
                                                 })).values();
over 4 years ago · Santiago Trujillo Report

0

An alternative to using string conncatenation for the intermediate hashmap that provides more flexibility could be to use an Entry. This would allow you to change your grouping types and handles the case of null values if you wrap the key or value in Optional.ofNullable. It does have the drawback of limiting you to only two elements to group by.

Customer custa = new Customer("A", "STANDARD", new BigDecimal("1000"), new BigDecimal("1500"));
Customer custa1 = new Customer("A", "VIP", new BigDecimal("2000"), new BigDecimal("2500"));
Customer custb = new Customer("B", "STANDARD", new BigDecimal("3000"), new BigDecimal("3500"));
Customer custc = new Customer("C", "STANDARD", new BigDecimal("4000"), new BigDecimal("4500"));
Customer custa2 = new Customer("A", "VIP", new BigDecimal("1500"), new BigDecimal("2500"));
Customer custa3 = new Customer(null, "VIP", new BigDecimal("1500"), new BigDecimal("2500"));
List<Customer> listCust = new ArrayList<>();
listCust.add(custa);
listCust.add(custa1);
listCust.add(custb);
listCust.add(custc);
listCust.add(custa2);
listCust.add(custa3);
Collection<Customer> result =  listCust.stream()
        .collect(Collectors.toMap(
                c -> Map.entry(Optional.ofNullable(c.getName()), c.getType()),
                Function.identity(),
                (c1, c2) -> new Customer(c1.getName(),
                        c1.getType(),
                        c1.getTotal().add(c2.getTotal()),
                        c1.getBalance().add(c2.getBalance()))))
        .values();
System.out.println(result);

outupt (inserted newlines for readability)

[
    Customer{name='null', type='VIP', total=1500, balance=2500},
    Customer{name='B', type='STANDARD', total=3000, balance=3500},
    Customer{name='C', type='STANDARD', total=4000, balance=4500},
    Customer{name='A', type='VIP', total=3500, balance=5000},
    Customer{name='A', type='STANDARD', total=1000, balance=1500}
]
over 4 years ago · Santiago Trujillo Report

0

You can do it using toMap using the merge function, stream the customer list and collect them into Map using name-type as key, and use the merge function, to sum up the total and balance for customers having same key

Collection<Customer> result = listCust.stream()
            .collect(Collectors.toMap(cu -> cu.getName() + "-" + cu.getType(),
                    Function.identity(), (c1, c2) -> {
                        c1.setTotal(c1.getTotal().add(c2.getTotal()));
                        c1.setBalance(c1.getBalance().add(c2.getBalance()));
                        return c1;
                    })).values();
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!