2017-06-29 141 views
2

例如,我有一个学生的学期和科目列表。按多个值分组

Subject Semester Attendee 
--------------------------------- 
ITB001 1   John 
ITB001 1   Bob 
ITB001 1   Mickey 
ITB001 2   Jenny 
ITB001 2   James 
MKB114 1   John 
MKB114 1   Erica 

当我需要他们组与Stream api一个值,我可以做类似的东西;

Map<String, List<Student>> studlistGrouped = 
    studlist.stream().collect(Collectors.groupingBy(w -> w.getSubject())); 

它确实有效。但是,当我想通过两个或多个值(如Sql句柄)对它们进行分组时,我无法弄清楚我需要做什么。

回答

1

一种方法是按类来分组,其中包含要分组的所有字段。这个类必须实现hashCodeequals使用所有这些字段才能按预期工作。

在您的例子,这将是:

public class SubjectAndSemester { 

    private final String subject; 

    private final int semester; // an enum sounds better 

    public SubjectAndSemester(String subject, int semester) { 
     this.subject = subject; 
     this.semester = semester; 
    } 

    // TODO getters and setters, hashCode and equals using both fields 
} 

然后,你应该在你Student类创建这种方法:

public SubjectAndSemester bySubjectAndSemester() { 
    return new SubjectAndSemester(subject, semester); 
} 

现在,你可以组分别如下:

Map<SubjectAndSemester, List<Student>> studlistGrouped = studlist.stream() 
    .collect(Collectors.groupingBy(Student::bySubjectAndSemester)); 

这创建了一个一级学生组。


有,不需要你使用Tuple或创建一个新的类组的另一种选择。我的意思是,你可以让学生的ň -level分组,利用下游groupingBy收藏家:

Map<String, Map<Integer, List<Student>>> studlistGrouped = studlist.stream() 
    .collect(Collectors.groupingBy(Student::getSubject, 
     Collectors.groupingBy(Student::getSemester))); 

这将创建一个2级分组,所以现在返回的结构图的列表的地图。如果你能忍受这一点,即使对更多层次进行分组,也可以避免创建一个充当地图关键字的类。

+0

非常感谢您的回答。你的答案看起来不错,但我的问题是我在这里简化了我的例子。基于用户选择,我不应该按组或应该由多达8个变量组成。在您的第一个解决方案中,我应该为每种可能性创建数千种不同的组合。 – drJava

+0

@drJava不一定......你可以用你最需要细化的场景中的8个领域创建一个班级。然后,如果用户没有选择要分组的8个字段,只需将未选择的字段设置为null,并使得hashCode和equals就像这些空字段不存在一样,即“hashCode”对于一个空字段应该是0.而对于'equals'只是比较'null'。 Eclipse和IntelliJ会自动为您执行此操作。 –

+0

这意味着,我需要在您的示例中只创建一个像bySubjectAndSemester这样的方法,并且不应将其分组的字段应该设置为null,其余部分与您在评论中写入的内容类似。 – drJava

0

您可以创建一个计算字段是两列

的组合
Map<String, List<Student>> studlistGrouped = 
    studlist.stream().collect(Collectors.groupingBy(w -> w.getSubject() + "-" w.getAttendee())); 

编辑:
另一个更“合适”的解决方案:Accoridng到this blog post,你需要定义一个Tuple类,可以保持两列:

class Tuple { 
    String subject; 
    String attendee; 
} 
Map<String, List<Student>> studlistGrouped = 
    studlist.stream().collect(Collectors.groupingBy(w -> new Tuple(w.getSubject(), w.getAttendee()))); 
+0

我会尝试一下,并给它一个反馈。感谢您的回答。 – drJava

+0

这里,在这个例子中我简化了我的例子。实际的实施将是这样的;基于用户输入,它可能不会被分组或直到8个字段,因此可以进行分组。我认为这个元组的例子可能更适合我的情况。 – drJava

+1

...其惊人的谷歌搜索引擎是如何有用... –