【问题标题】:Java Collection - Group, Combine and Dedup by MaximumJava 集合 - 按最大值分组、组合和重复数据删除
【发布时间】:2021-09-26 07:27:59
【问题描述】:

我有以下课程:

public class Student {  
    String studentId;
    List<Subject> subjects;
    //+Getters, setters, constructors
}

public class Subject {  
    int subjectId;
    String grade;   
    int marks;
    //+Getters, setters, constructors
}

示例输入:

Student S1 subjects=[1, A, 90], [2, B, 80], [2, C, 70]
Student S1 subjects=[2, A+, 95], [3,C,70]
Student S2, subjects=[1, D, 50]
Student S2, subjects=[1, D, 50]

示例输出:

Student S1 subjects=[1, A, 90], [2, A+, 95], [3,C,70]  //Subject 2 is selected based on highest marks
Student S2, subjects=[1, D, 50] //Avoided duplicate for same mark

我想实现一个合并和重复数据删除功能。 该函数应该只返回一个 StudentId 一次。 每个 StudentID 应该包含在该学生中只出现一次的每个 subjectID。应根据最高分选择主题ID。

public List<Student> consolidate (List<Student> students)
    {
        List<Student> consolidatedStudents = new ArrayList<Student>();
        //???
        return consolidatedStudents;
    }

我怎样才能以最有效的方式实现这一目标?

用于测试的示例主类

    public class Main {
    
    public static void main(String args[])
    {
        List<Subject> s1Subjects_1 = new ArrayList<>();
        List<Subject> s1Subjects_2 = new ArrayList<>();
        Subject s1Physics = new Subject(1,"A",90);
        Subject s1Chemistry_1 = new Subject(2,"B",80);      
        Subject s1Chemistry_2 = new Subject(2,"C",70);
        Subject s1Chemistry_3 = new Subject(2,"A+",95);
        Subject s1Biology = new Subject(3,"C",70);
        
        s1Subjects_1.add(s1Physics);
        s1Subjects_1.add(s1Chemistry_1);
        s1Subjects_1.add(s1Chemistry_2);
        s1Subjects_2.add(s1Chemistry_3);
        s1Subjects_2.add(s1Biology);
        
        List<Subject> s2Subjects_1 = new ArrayList<>();
        List<Subject> s2Subjects_2 = new ArrayList<>();
        Subject s2Physics_1 = new Subject(1,"D",50);
        Subject s2Physics_2 = new Subject(1,"D",50);
        s2Subjects_1.add(s2Physics_1);
        s2Subjects_2.add(s2Physics_2);
        
        Student s1_1 = new Student("s1", s1Subjects_1);
        Student s1_2 = new Student("s1", s1Subjects_2);
        Student s2_1 = new Student("s2", s2Subjects_1);
        Student s2_2 = new Student("s2", s2Subjects_2);
        
        List<Student> input = new ArrayList<>();
        input.add(s1_1);
        input.add(s1_2);
        input.add(s2_1);
        input.add(s1_2);        
        
        List<Student> output = consolidate(input);
    }
    
    public static List<Student> consolidate (List<Student> students)
    {
        List<Student> consolidatedStudents = new ArrayList<Student>();
        //
        //???
        //
        return consolidatedStudents;
    }

}

【问题讨论】:

    标签: java collections stream max


    【解决方案1】:

    这是一种使用流的有趣方式..

    这里我使用Collectors.toMap来构建一个临时的数据结构映射 学生 ID 到科目列表。我正在使用辅助合并功能合并主题列表。

    合并功能根据分数选择最佳主题。

    public static List<Student> consolidate(List<Student> students) {
        Map<String, List<Subject>> map = students.stream()
                .collect(Collectors.toMap(Student::getStudentId,
                        Student::getSubjects,
                        (subjects1, subjects2) -> merge(subjects1, subjects2)));
        return map.entrySet()
                .stream()
                .map(e -> new Student(e.getKey(), e.getValue()))
                .collect(Collectors.toList());
    }
    

    merge 函数为两个主题构建一个临时映射(主题 id -> 主题的映射),并使用 Map#merge 将第二个映射到第一个。对于具有相同 id 的科目,它会选择得分最高的科目。

    private static List<Subject> merge(List<Subject> subjects1, List<Subject> subjects2) {
        Map<Integer, Subject> subjects1ById = new HashMap<>(subjectsMap(subjects1));
        Map<Integer, Subject> subjects2ById = subjectsMap(subjects2);
       
        subjects2ById.forEach((subId, sub) -> subjects1ById.merge(subId, sub,
                (sub1, sub2) -> pickBest(sub1, sub2)));
        return new ArrayList<>(subjects1ById.values());
    }
    
    private static Map<Integer, Subject> subjectsMap(List<Subject> subjects) {
        return subjects.stream()
                .collect(Collectors.toMap(Subject::getSubjectId, Function.identity(),
                        (sub1, sub2) -> pickBest(sub1, sub2)));
    }
    
    private static Subject pickBest(Subject s1, Subject s2) {
        return s1.getMarks() > s2.getMarks() ? s1 : s2;
    }    
    

    【讨论】:

    • 太棒了,非常感谢你。我是流媒体新手,无法思考这些问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    • 2018-04-02
    相关资源
    最近更新 更多