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)
}
}
-
What is the question?kozmo– kozmo06/03/2020 12:26:01Commented Jun 3, 2020 at 12:26
-
My expected output and actual output from code are differentsudhir– sudhir06/03/2020 12:35:56Commented Jun 3, 2020 at 12:35
-
Check expected output: Above logic is returning below result: values in above codesudhir– sudhir06/03/2020 12:43:16Commented Jun 3, 2020 at 12:43
4 Answers 4
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);
}
}
-
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"sudhir– sudhir06/03/2020 13:07:40Commented 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.Ankur– Ankur06/03/2020 16:57:29Commented Jun 3, 2020 at 16:57
-
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.
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));
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
}
}`