2017-06-29 144 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

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