Java - 如何使用List组织Map作为值

时间:2018-04-05 01:02:16

标签: java hashmap

我遇到了一个问题,我必须组织一个值为列表的地图。我得到了一个名为学生的预先写好的课程。我必须编写一个返回地图的方法,如下所示:

Map<String, List<Student>> map;

键应该代表学生注册的课程,列表应该代表该课程的学生。我获得了一份学生名单,并且必须按照从最低到最高的GPA顺序将这些学生组织到地图中。

这是我给的学生班:

public static class Student {
    private String name;
    private int zip;
    private Map<String, Double> grades;

    public Student(String name, int zip) {
        this.name = name;
        this.zip = zip;
        grades = new HashMap<String, Double>();
    }

    public void addGrade(String n, double d) {
        grades.put(n, d);
    }

    public double getGrade(String n) {
        return grades.get(n);
    }

    public Map<String, Double> getGrades(){
        return grades;
    }

    public double getOverAllGrade() {
        //To do as part of the test
        double totalGrade = 0.0;
        for (String grade : grades.keySet()) {
            totalGrade += getGrade(grade);
        }
        double average = totalGrade / grades.size();
        return average;
    }

    public int getZip() {
        return zip;
    }

    public String getName() {
        return name;
    }

    public boolean equals(Object o) {
        Student s = (Student)o;
        return zip == s.zip && name.equals(s.name);
    }

    public String toString() {
        return name+" "+zip;
    }

}

我已经尝试使用以下代码解决此问题(我已经包含了该方法的目的,以帮助消除混淆):

/**
 * return a Map<String, List<Student>> of all the classes mapped
 * to a List of Students in the order of their grades from lowest
 * to highest
 * 
 * @param students List<Student> the students in the school
 * @return Map<String, List<Student>> {"class name":{Student1, Student2}, "class 2":{Student3, Student4"}} 
 */
public static Map<String, List<Student>> organizeByClass(List<Student> students){
    HashMap<String, List<Student>> map = new HashMap<String, List<Student>>();
    for (Student student : students) {
        for (String className : student.getGrades().keySet()) {
            if (!map.keySet().contains(className)) {                                           // If the class hasn't been added, it will be added
                ArrayList<Student> studentsInClass = new ArrayList<Student>();
                studentsInClass.add(student);
                map.put(className, studentsInClass);
            } else {
                if (student.getOverAllGrade() < map.get(className).get(0).getOverAllGrade()) { // Sorts the students by GPA
                    map.get(className).add(0, student);
                } else {
                    map.get(className).add(student);
                }
            }
        }
    }
    return map;
}

这是我正在使用的测试用例(它正在使用JUnit库):

@Test
public void organizeByClassTest1() {
    List<Student> col = new ArrayList<Student>();
    col.add(createStudent("Bob", 12345));
    col.add(createStudent("Earl", 67890));
    col.add(createStudent("Roman", 12345));
    col.add(createStudent("Victor", 45678));
    col.add(createStudent("Nick", 67890));
    col.add(createStudent("Aaron", 12345));
    col.add(createStudent("Marissa", 45678));
    col.add(createStudent("Enoch", 12345));
    col.add(createStudent("Spencer", 12345));
    col.add(createStudent("Britt", 45678));
    Student s1 = createStudent("Justin", 67890);
    col.add(s1);
    Map<String, List<Student>> map1 = new HashMap<String, List<Student>>();
    Random r = new Random();
    List<Student> g1 = new ArrayList<Student>();
    List<Student> h1 = new ArrayList<Student>();
    List<Student> he1 = new ArrayList<Student>();
    List<Student> cs1 = new ArrayList<Student>();
    List<Student> p1 = new ArrayList<Student>();

    map1.put("Geometry", g1);
    map1.put("History", h1);
    map1.put("Home Economics", he1);
    map1.put("Physics", p1);
    map1.put("Computer Science", cs1);
    for (Student s : col) {
        if (r.nextInt(5) > 0) {
            s.addGrade("Geometry", r.nextDouble() * 4);
            g1.add(s);
        }
        if (r.nextInt(5) > 0) {

            s.addGrade("Computer Science", r.nextDouble() * 4);
            cs1.add(s);
        }
        if (r.nextInt(5) > 0) {
            s.addGrade("History", r.nextDouble() * 4);
            h1.add(s);
        }
        if (r.nextInt(5) > 0) {
            s.addGrade("Home Economics", r.nextDouble() * 4);
            he1.add(s);
        }
        if (r.nextInt(5) > 0) {
            s.addGrade("Physics", r.nextDouble() * 4);
            p1.add(s);
        }
    }
    Comparator<Student> c = new Comparator<Student>() {
        public int compare(Student s1, Student s2) {
            return (int) (s1.getOverAllGrade()-s2.getOverAllGrade());
        }
    };
    Collections.sort(p1, c );
    Collections.sort(he1, c );
    Collections.sort(h1, c );
    Collections.sort(cs1, c );
    Collections.sort(g1, c );
    Map<String,List<Student>> result = MappingAssessment.organizeByClass(col);
    assertEquals(map1,result);
}

我不明白为什么我写的代码不正确。所有帮助表示赞赏。

谢谢,Steward。

2 个答案:

答案 0 :(得分:1)

您没有正确排序学生,因为任何不是最高年级的学生都会被发送到列表的后面。

答案 1 :(得分:1)

您还应该使用LinkedList<Student>而不是ArrayList<Student>,因为每次遇到新学生时都会进行多次插入。每次学生列表​​已经存在于地图中(您的else {...}块),您需要循环并对列表进行排序,而不是添加到列表的后面。