Home > Net >  Java collection grouping with custom key
Java collection grouping with custom key

Time:04-26

I have a list of students studentList and i want to seperate them based on their class and section into a Map<CustomKey, List<Student>>.

class Student {
public String Name;
public String Class;
public String Section;
}

I have a custom Key Class

class CustomKey {
public String Class;
public String Section;
}

I'm trying to group them using this, but we can clearly see what I'm doing wrong.

studentList.stream().collect(Collectors.groupingBy(x -> new CustomKey(x.Class, x.Section)));

The expression inside groupingBy is incorrect. Extending the Student Class is not allowed :(

I want to create this output

{
    {"ClassA", "SectionA"}: [{name, class, section}, {name, class, section}],
    {"ClassA", "SectionB"}: [{name, class, section}],
    {"ClassB", "SectionA"}: [{name, class, section}, {name, class, section}],
}

My knowledge is very limited on JAVA. And any help/pointers are welcomed. Also, Apologies for the messed-up cases.

CodePudding user response:

i used your code exactly like below and it works for me

 public void testCustomGroupBy(){
    List<Student> studentList = new ArrayList<>();
    studentList.add(new Student("name_1","class_1","section_1"));
    studentList.add(new Student("name_2","class_1","section_1"));
    studentList.add(new Student("name_3","class_2","section_1"));
    studentList.add(new Student("name_4","class_2","section_2"));
    studentList.add(new Student("name_5","class_2","section_2"));
    Map<CustomKey, List<Student>> studentsBySection = studentList.stream().collect(Collectors.groupingBy(x -> new CustomKey(x.getClassName(), x.getSection())));
    studentsBySection.entrySet().forEach(System.out::print);
}

create your pojo like below

class Student {
public String name;
public String className;
public String section;
// getters and setters

public Student(String name, String className, String section) {
    this.name = name;
    this.className = className;
    this.section = section;
}

}

class CustomKey {
public String className;
public String section;
// getters and setters

public CustomKey(String className, String section) {
    this.className = className;
    this.section = section;
}

}

output

CustomKey(className=class_2, section=section_2)=[Student(name=name_4, className=class_2, section=section_2), Student(name=name_5, className=class_2, section=section_2)]
CustomKey(className=class_2, section=section_1)=[Student(name=name_3, className=class_2, section=section_1)]
CustomKey(className=class_1, section=section_1)=[Student(name=name_1, className=class_1, section=section_1), Student(name=name_2, className=class_1, section=section_1)]

CodePudding user response:

Well, CustomKey is matched by its equals method, which you don't have overridden. If you implement equals (and also hashCode) properly, then it'll work.

What's even better, is to create a record for CustomKey:

public record CustomKey(String className, String section) { }

This'll let the compiler auto-generate its equals and hashCode implementations for free, as well as getters, the canonical constructor and the toString method. The above record definition is equivalent to this:

public final class CustomKey {

    private final String className;
    private final String section;

    public CustomKey(String className, String section) {
        this.className = className;
        this.section = section;
    }

    public String className() {
        return className;
    }

    public String section() {
        return section;
    }

    @Override
    public boolean equals(Object o) {
        return getClass() == o.getClass()
            && Objects.equals(className, o.className)
            && Objects.equals(section, o.section);
    }

    @Override
    public int hashCode() {
        return Objects.hash(className, section);
    }

    @Override
    public String toString() {
        return "CustomKey[className="   className   ", section="   section   "]";
    }
  • Related