简体   繁体   中英

Java - Convert list of objects to map of map data structure

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)
     }
 }

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);
    }
 }

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, eg 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 } }`

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM