1

I have two ArrayLists of ClassRoom object and below shows the ClassRoom class :

public class ClassRoom {

    private String className; // className is unique here
    private List<Student> students = new ArrayList<>();

    public ClassRoom(String className, List<Student> students) {
        this.className = className;
        this.students = students;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }

    @Override
    public String toString() {

        String ss = "[";
        for (int i = 0; i < students.size(); i++) {
            ss += "{name:'" + students.get(i).getName() + "',age:" + students.get(i).getAge() + "}";
            ss += (i == (students.size() - 1)) ? "" : ",";
        }
        ss += "]";
        return "{'" + className + "':" + ss + "}";
    }

}

ClassRoom class contains className String property and List of Student object which describes below:

public class Student {

    private String name; // name is unique here
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

I have created my two lists of ClassRoom object like below :

List<ClassRoom> list1 = new ArrayList<>();

list1.add(new ClassRoom("A", Arrays.asList(new Student("Sam", 20), new Student("Peter", 40), new Student("Aaron", 15))));
list1.add(new ClassRoom("B", Arrays.asList(new Student("Ronnie", 33), new Student("Daniel", 41), new Student("Gabe", 35))));
list1.add(new ClassRoom("C", Arrays.asList(new Student("Fabian", 42), new Student("Edgar", 33))));
list1.add(new ClassRoom("D", Arrays.asList(new Student("Peter", 39), new Student("Calvin", 45))));

List<ClassRoom> list2 = new ArrayList<>();

list2.add(new ClassRoom("A", Arrays.asList(new Student("Sam", 26), new Student("Aaron", 18))));
list2.add(new ClassRoom("B", Arrays.asList(new Student("Daniel", 38), new Student("Eddy", 29))));
list2.add(new ClassRoom("C", Arrays.asList(new Student("Fabian", 42), new Student("Edgar", 33))));

So my final task is to create a new List of ClassRoom object like below :

List<ClassRoom> mergedList = merge(list1, list2);

for (ClassRoom classRoom : mergedList) {
    System.out.println(classRoom.toString());
    /* Expected output here
    {'A':[{name:'Sam',age:26},{name:'Peter',age:40},{name:'Aaron',age:18}]}
    {'B':[{name:'Ronnie',age:33},{name:'Daniel',age:38},{name:'Gabe',age:35},{name:'Eddy',age:29}]}
    {'C':[{name:'Fabian',age:42},{name:'Edgar',age:33}]}
    {'D':[{name:'Peter',age:39},{name:'Calvin',age:45}]}
   */
}

And below explains my merge method:

public static List<ClassRoom> merge(List<ClassRoom> listA, List<ClassRoom> listB) {

      ArrayList<ClassRoom> collect = Stream.of(listA, listB).collect(ArrayList<ClassRoom>::new, (item1, item2) -> {
          item2.forEach((c2) -> {
            item1.forEach((c1) -> {
                if (c2.getClassName().equalsIgnoreCase(c1.getClassName())) {
                    // Student list update goes here
                } else {
                    item1.add(c2);
                }
            });
        });
      }, (item1, item2) -> {

      });

    return collect;
 }

Problem I am having so far is resulting an empty list after the merge method call. Any suggestions would be appreciated.

1
  • this could be helped. And you dont need ot make both forEach loops in collect Commented Mar 27, 2021 at 11:06

2 Answers 2

2
  1. Override the equals and hashCode methods in Student on name.
@Override
public boolean equals(Object obj) {
    return Objects.equals(name, ((Student) obj).getName());
}

@Override
public String toString() {
    return "name: " + name + ", age: " + age;
}
  1. Override the equals and hashCode methods in ClassRoom using the default implementation suggested by your IDE.
  2. Collect list2 into a Map<String, List<Student>> map and process each element of list1 as shown below:

Map<String, List<Student>> map = list2.stream()
            .collect(Collectors.toMap(ClassRoom::getClassName, ClassRoom::getStudents));

list1.forEach(e -> map.merge(e.getClassName(),
                                Stream.of(map.getOrDefault(e.getClassName(), e.getStudents()), e.getStudents())
                                .flatMap(List::stream)
                                .distinct()
                                .collect(Collectors.toList()),
                                    (v1, v2) -> v2)
                            );

Output:

{A=[name: Sam, age: 26, name: Aaron, age: 18, name: Peter, age: 40], B=[name: Daniel, age: 38, name: Eddy, age: 29, name: Ronnie, age: 33, name: Gabe, age: 35], C=[name: Fabian, age: 42, name: Edgar, age: 33], D=[name: Peter, age: 39, name: Calvin, age: 45]}

ONLINE DEMO

Sign up to request clarification or add additional context in comments.

Comments

1

You can do like this:

public static List<ClassRoom> merge(List<ClassRoom> listA, List<ClassRoom> listB) {
    Map<String, Set<Student>> map = new HashMap<>();
    listA.forEach(item -> map.put(item.getClassName(), new HashSet<>(item.getStudents())));
    for (ClassRoom classRoom : listB) {
        Set<Student> set = map.getOrDefault(classRoom.getClassName(), new HashSet<>());
        set.addAll(classRoom.getStudents());
        map.put(classRoom.getClassName(), set);
    }
    List<ClassRoom> list = new ArrayList<>();
    map.forEach((k, v) -> list.add(new ClassRoom(k, new ArrayList<>(v))));
    return list;
}

and add below in Student:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Student)) return false;
    Student student = (Student) o;
    return getName() != null ? getName().equals(student.getName()) : student.getName() == null;
}
@Override
public int hashCode() {
    return getName() != null ? getName().hashCode() : 0;
}

Comments

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.