Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java collection - group by multiple attributes

I have a Java class:

class Person {
  String firstName;
  String lastName;
  int income;

public Person(String firstName, String lastName, int income)
{
  this.firstName = firstName;
  this.lastName = lastName;
  this.income = income;
}

I have a Collection<Person>, with 4 x Person objects:

  Collection<Person> persons = new ArrayList<>();
  persons.add(new Person("John", "Smith", 5));
  persons.add(new Person("Mary", "Miller", 2));
  persons.add(new Person("John", "Smith", 4));
  persons.add(new Person("John", "Wilson", 4));

I want to make a new Collection instance, but from the elements with the same "firstName" and "lastName", make 1 element, and the result "income" will be the sum of the "incomes" of each element. So, for this particular case, the resulting collection will have 3 elements, and "John Smith" will have the "income" = 9.

In SQL, the equivalent query is:

SELECT FIRSTNAME, LASTNAME, SUM(INCOME) FROM PERSON GROUP BY FIRSTNAME, LASTNAME

I found only answers which contain Map as result, and "key" contains the column(s) used for grouping by. I want to obtain directly a similar type of collection from the initial (ArrayList<Person>), and not a Map, because if in my collection I have millions of elements, it will decrease the performance of the code. I know it was easier if I worked on SQL side, but in this case I must work on Java side.

like image 874
Catalin Vladu Avatar asked Jul 17 '26 16:07

Catalin Vladu


1 Answers

I don't know if that is the most beautiful solution, but you can try to groupBy firstName and lastName with a delimiter between them, let's say .. After you collect your data into Map<String, Integer> that contains your firstName.lastName, you create new list of Person from it.

 List<Person> collect = persons.stream()
            .collect(Collectors.groupingBy(person -> person.getFirstName() + "." + person.getLastName(),
                    Collectors.summingInt(Person::getIncome)))
            .entrySet().stream().map(entry -> new Person(entry.getKey().split(".")[0],
                                                                      entry.getKey().split(".")[1],
                                                                      entry.getValue()))
            .collect(Collectors.toList());
like image 147
Schidu Luca Avatar answered Jul 19 '26 06:07

Schidu Luca