Home > Net >  Split object list according to some fields
Split object list according to some fields

Time:07-26

I need to split an object list according to the value of certain fields by grouping them.

For a student object :

    public class Student {
       private int id;
       private String section;
       private Integer age;
       private String city;
}

I had a list of

List<Student> list = new ArrayList()<>;
list.add(new Student(1,"Biology", 23, "New York"));
list.add(new Student(2,"Mathematics", 22, "Chicago"));
list.add(new Student(3,"Technology", 23, "New York"));
list.add(new Student(4,"Biology", 23, "New York"));
list.add(new Student(5,"Technology", 23, "New York"));
list.add(new Student(6,"Biology", 21, "Chicago"));

And I want to split it on lists with the same section/age/city.

Means that in my example I'll have 4 lists : (1 and 4), 2, (3 and 5), 6.

There is any easy way to do it with Streams?

Thank you

CodePudding user response:

Use Collectors.groupingBy and create a common key. This returns a Map that needs iterated to get the groups.

final Map<String, List<Student>> collect = list.stream()
    .collect(Collectors.groupingBy(student -> String.format("%s:%d:%s", student.getSection(), student.getAge(), student.getCity())));
int group = 0;
for (Map.Entry<String, List<Student>> e : collect.entrySet()) {
  System.out.println(  group   ": "   e.getValue());
}

1: [Student{id=1, section='Biology', age=23, city='New York'}, Student{id=4, section='Biology', age=23, city='New York'}]
2: [Student{id=3, section='Technology', age=23, city='New York'}, Student{id=5, section='Technology', age=23, city='New York'}]
3: [Student{id=6, section='Biology', age=21, city='Chicago'}]
4: [Student{id=2, section='Mathematics', age=22, city='Chicago'}]

CodePudding user response:

You can use a built-in collector groupingBy() to partition the stream into groups by string them into a map.

A good practice in such cases is to define a record (or a class) to use it as a key. "Quick and dirty" alternatives are to generate a key using string concatenation, or by using a list of Object type. Both are good as examples, proofs of concepts. Concatenation is not very reliable, and using collection as a key isn't a good practice.

I'll go with a Java 16 record:

public record Key(String section, int age, String city) {
    public Key(Student student) {
        this(student.getSection(), student.getAge(), student.getCity());
    }
}

The code for splitting the list of Students into groups based on the Key which encompasses section, age and city might look like that:

Collection<List<Student>> groups = list.stream()
    .collect(Collectors.groupingBy(Key::new))
    .values();
        
groups.forEach(System.out::println);

Output:

[Student{id=3, section='Technology', age=23, city='New York'}, Student{id=5, section='Technology', age=23, city='New York'}]
[Student{id=6, section='Biology', age=21, city='Chicago'}]
[Student{id=2, section='Mathematics', age=22, city='Chicago'}]
[Student{id=1, section='Biology', age=23, city='New York'}, Student{id=4, section='Biology', age=23, city='New York'}]
  • Related