0

I am trying to convert List of objects data structure in to Map of Maps.

Map<String, Map<Integer, StudentModel>>

String is sports variable

Integer is orderId.

My logic returned below value as shown below. I am looking for better way of achieving this.

@Data
@Builder
public class Student { 
 private String name;
 private int rollno;
 private int studentage;
 private String sports;
 private int orderId;
} 
@Data
@Builder
public class StudentModel {
 private String name;
 private int rollno;
 private int studentage;
 private String sports;
}

Created same data and added to list:

arraylist.add(new Student(223, "Zebra", 26, "cricket", 1));
arraylist.add(new Student(245, "Rahul", 24, "cricket", 2));
arraylist.add(new Student(209, "Ajeet", 32, "cricket", 3));
arraylist.add(new Student(140, "Abhay", 28, "basketball", 4));
arraylist.add(new Student(270, "Ranger", 29, "basketball", 5));
arraylist.add(new Student(250, "Ranger1", 39, "basketball",6));
Collections.sort(arraylist, Comparator.comparing(Student::getOrderId));

My expected output:

{
 cricket={
 1=Student(sports=cricket, rollno=223, name=Zebra, studentage=26), 
 2=Student(sports=cricket, rollno=245, name=Rahul, studentage=24), 
 3=Student(sports=cricket, rollno=209, name=Ajeet, studentage=32)
 }, 
 basketball={
 4=Student(sports=basketball, rollno=140, name=Abhay, studentage=28), 
 5=Student(sports=basketball, rollno=270, name=Ranger, studentage=29), 
 6=Student(sports=basketball, rollno=250, name=Ranger1, studentage=39)
 }
 }

Logic written:

public Map<String, Map<Integer, StudentModel>> studentModel() {
 Map<Integer, StudentModel> studentMap = new LinkedHashMap<>();
 Map<String, Map<Integer, StudentModel>> inputMap = new LinkedHashMap<>();
 for (Student student : arraylist) {
 StudentModel studentModel = StudentModel.builder().name(student.getName)
 .rollno(student.getRollno)
 .studentage(student.getStudentage)
 .sports(student.getSports)
 studentMap.put(studentModel.getOrderId, studentModel);
 inputMap.put(student.getSports, studentMap);
 }
 }

Above logic is returning below result:

 {
 cricket={
 1=Student(sports=cricket, rollno=223, name=Zebra, studentage=26), 
 2=Student(sports=cricket, rollno=245, name=Rahul, studentage=24), 
 3=Student(sports=cricket, rollno=209, name=Ajeet, studentage=32),
 4=Student(sports=basketball, rollno=140, name=Abhay, studentage=28), 
 5=Student(sports=basketball, rollno=270, name=Ranger, studentage=29), 
 6=Student(sports=basketball, rollno=250, name=Ranger1, studentage=39)
 }, 
 basketball={
 1=Student(sports=cricket, rollno=223, name=Zebra, studentage=26), 
 2=Student(sports=cricket, rollno=245, name=Rahul, studentage=24), 
 3=Student(sports=cricket, rollno=209, name=Ajeet, studentage=32),
 4=Student(sports=basketball, rollno=140, name=Abhay, studentage=28), 
 5=Student(sports=basketball, rollno=270, name=Ranger, studentage=29), 
 6=Student(sports=basketball, rollno=250, name=Ranger1, studentage=39)
 }
 }
Lino
20k6 gold badges54 silver badges72 bronze badges
asked Jun 3, 2020 at 12:04
3
  • What is the question? Commented Jun 3, 2020 at 12:26
  • My expected output and actual output from code are different Commented Jun 3, 2020 at 12:35
  • Check expected output: Above logic is returning below result: values in above code Commented Jun 3, 2020 at 12:43

4 Answers 4

1

Problem is you are using only a single instance/memory of studentMap for each entry of inputMap, hence you see all 6 student entries against each 'sport' key because each of those inputMap entry values are pointing to same reference value of studentMap and thus observes changes done by any sports type key.

What you want to do here is to create new memory of studentMap for each type of 'sport', so. You can try doing something like this:

public Map<String, Map<Integer, StudentModel>> studentModel() {
 Map<Integer, StudentModel> studentMap;
 Map<String, Map<Integer, StudentModel>> inputMap = new LinkedHashMap<>();
 for (Student student : arraylist) {
 StudentModel studentModel = StudentModel.builder().name(student.getName)
 .rollno(student.getRollno)
 .studentage(student.getStudentage)
 .sports(student.getSports)
 // This would create new memory for each type of sport
 studentMap = inputMap.getOrDefault(student.getSports, new LinkedHashMap<Integer, StudentModel>());
 studentMap.put(studentModel.getOrderId, studentModel);
 inputMap.put(student.getSports, studentMap);
 }
 }
answered Jun 3, 2020 at 12:29
3
  • Cool. This worked for me. Thanks Can you explain what do you mean by "you are using only a single instance/memory of studentMap for each entry of inputMap" Commented Jun 3, 2020 at 13:07
  • @sudhir What I meant by that is all the inputMap values are pointing to same reference for Map<Integer, StudentModel> because clearly studentMap was created just once. Hence, whenever studentMap gets updated, its reference starts reflecting those changes wherever we are using it. As a result, output had 6 student records against each sports type. Commented Jun 3, 2020 at 16:57
  • Got it. Thank you Commented Jun 4, 2020 at 2:58
1

You need to create a new map for each sport:

public Map<String, Map<Integer, StudentModel>> studentModel() {
 Map<String, Map<Integer, StudentModel>> inputMap = new LinkedHashMap<>();
 for (Student student : arraylist) {
 StudentModel studentModel = StudentModel.builder().name(student.getName)
 .rollno(student.getRollno)
 .studentage(student.getStudentage)
 .sports(student.getSports)
 // create a new map and insert it into the outer map if it's not already there
 Map<Integer, StudentModel> studentMap = inputMap.computeIfAbsent(student.getSports, k -> new LinkedHashMap<>());
 studentMap.put(studentModel.getOrderId, studentModel);
 }
 }

Unrelated to the issue but fields should be accessed with getter methods, e.g. instead of student.getSports you should have a private sports field with a getSports() method.

answered Jun 3, 2020 at 12:36
1

The groupingBy method does exactly what you need. You want to group the students in your original arraylist based on their sport:

Map<String, List<Student>> inputMap = arraylist.stream().collect(Collectors.groupingBy(Student::getSports));
answered Jun 3, 2020 at 12:40
0

This is happening because you are using same instance of student map in both the category.

here is your code

 public Map<String, Map<Integer, StudentModel>> studentModel() {
 Map<Integer, StudentModel> studentMap = new LinkedHashMap<>();
 Map<String, Map<Integer, StudentModel>> inputMap = new LinkedHashMap<>();
 for (Student student : arraylist) {
 StudentModel studentModel = StudentModel.builder().name(student.getName)
 .rollno(student.getRollno)
 .studentage(student.getStudentage)
 .sports(student.getSports)
 studentMap.put(studentModel.getOrderId, studentModel);//logical error here
 inputMap.put(student.getSports, studentMap);//error here
 }
}

use below code for desired result

public Map<String, Map<Integer, StudentModel>> studentModel() {
 Map<Integer, StudentModel> studentMap = new LinkedHashMap<>();
 Map<String, Map<Integer, StudentModel>> inputMap = new LinkedHashMap<>();
 for (Student student : arraylist) {
 if (inputMap.get(student.getSports())==null){
 studentMap = new LinkedHashMap<>();
 }else{
 studentMap = inputMap.get(student.getSports());
 }
 StudentModel studentModel = StudentModel.builder().name(student.getName)
 .rollno(student.getRollno)
 .studentage(student.getStudentage)
 .sports(student.getSports)
 studentMap.put(studentModel.getOrderId, studentModel);//error here
 inputMap.put(student.getSports, studentMap);//error here
 }
}`

answered Jun 3, 2020 at 13:03

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.