簡體   English   中英

Java-Stream - Collecor groupingBy() 如何將 Map 拆分為多個子圖

[英]Java-Stream - How Collecor groupingBy() to split a Map into multiple Submaps

我有以下Student object:

public class Student {
    private String gradeAndClass;
    private String gender;
    private String name;

    // getters, constructor, etc.
}

, but for the purpose of simplicity let's consider them to be strings.在原始代碼中,屬性gradeAndClassgender,但為了簡單起見,我們將它們視為字符串。

我有一個 map Map<String,Student> ,其中是唯一字符串,Student object。

我需要這個 map 拆分成一堆地圖Map<String,Student> ,所以結果應該是List<Map<String,Student>>的列表。

讓我們考慮以下示例:

Map<String, Student> data = new HashMap<>();

data.put("key1", new Student("class_1", "Boy", "Jo"));
data.put("key2", new Student("class_2", "Girl", "Alice"));
data.put("key3", new Student("class_1", "Girl", "Amy"));
data.put("key4", new Student("class_2", "Girl", "May"));
data.put("key5", new Student("class_1", "Boy", "Oscar"));
data.put("key6", new Student("class_2", "Boy", "Jimmy"));
data.put("key7", new Student("illegal class name", "Boy", "err1"));
data.put("key8", new Student("class_2", "not supported", "err2"));

有沒有一種簡單的方法可以先按gradeAndClass然后按gender拆分Map ,這樣結果將是一個包含以下子圖的列表:

  • 子圖 1:
"key1", ["class_1", "Boy", "Jo"]
"key5", ["class_1", "Boy", "Oscar"]
  • 子圖 2:
"key3", ["class_1", "Girl", "Amy"]
  • 子圖 3:
"key6", ["class_2", "Boy", "Jimmy"]
  • 子圖 4:
"key2", ["class_2", "Girl", "Alice"]
"key4", ["class_2", "Girl", "May"]

另外,我想將非法輸入匯總到單獨的 map:

  • 子圖 5:
"key7", ["illegal class name", "boy", "err1"]
"key8", ["class_2", "not supported", "err2"]

我試圖分別過濾與每個子圖相關的數據(利用原始代碼中的事實gradeAndClassgender是定義明確的枚舉),但效率非常低。

基本上,我已經對所有條件檢查進行了硬編碼,並且必須按每個gradeAndClassgender進行過濾和重新組合。 我還必須重申每個條目以獲取非法條目,以便將它們放入單獨的“錯誤映射”

抱歉,我對流很陌生,所以我知道我的解決方案絕對不可擴展,因此我正在尋找建議。 是否可以使用 stream groupingBy()來完成所有這些工作?

這是我用來生成單獨子圖的代碼:

Map<String, Student> submap = data.entrySet().stream()
    .filter(entry -> "class_1".equals(entry.getValue()) &&
                     (other conditions))
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue
    ));

要按年級性別對學生進行分組,我們需要一個結合這兩個屬性的 object。

為此,對於早期的 JDK 版本,我們可以使用 Java 16recordclass (或者,很少有快速和骯臟的選項,如List<Object>或串聯String但它不會再見你任何東西,所以我不建議去這條路線)。

record Key(String gradeAndClass, String gender) {}

作為第一步,我們需要創建一個輔助 map ,它將每個(對應於特定的年級和性別)與源映射的條目列表(包含字符串鍵和學生對象)相關聯。 這可以使用收集器groupingBy()來完成。

然后我們需要將輔助 map中的每個列表轉換為Map<String,Student>並將結果收集到列表中。

這就是它的實現方式:

List<Map<String, Student>> result = data.entrySet().stream()
    .collect(Collectors.groupingBy(
        entry -> new Key(entry.getValue().getGradeAndClass(),
                         entry.getValue().getGender())
    ))
    .values().stream()
    .map(list -> list.stream()
        .collect(Collectors.toMap(
            Map.Entry::getKey, Map.Entry::getValue
        ))
    ).toList(); // or .collect(Collectors.toList()) for JDK versions earlier than 16

為了將包含Student object 的條目與不正確的等級值或未指定的性別進行分組,您可以實現一個實用方法,該方法將包含用於發現此類錯誤對象並返回Key的特殊實例的條件邏輯(即實例化一次並定義為static final字段)。 如果 object 有效,則應返回“正常” Key

實現此方法后,只需將groupingBy()分類器function 替換為使用它的方法參考即可。

我們可以使用 Java 8 Streams groupingBy 方法來實現。 以下是示例代碼

Map<String, List<Map.Entry<String, Student>>> filters = data.entrySet()
                .stream()
                .collect(Collectors.groupingBy(entry -> entry.getValue().getGradeAndClass()));

Output 是

illegal class name=[key7=Student@2d98a335], 
class_2=[key2=Student@16b98e56, key6=Student@7ef20235, key4=Student@27d6c5e0, key8=Student@4f3f5b24]
class_1=[key1=Student@15aeb7ab, key5=Student@7b23ec81, key3=Student@6acbcfc0]}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM