[英]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.在原始代碼中,屬性gradeAndClass和gender是,但為了簡單起見,我們將它們視為字符串。
我有一個 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
,這樣結果將是一個包含以下子圖的列表:
"key1", ["class_1", "Boy", "Jo"]
"key5", ["class_1", "Boy", "Oscar"]
"key3", ["class_1", "Girl", "Amy"]
"key6", ["class_2", "Boy", "Jimmy"]
"key2", ["class_2", "Girl", "Alice"]
"key4", ["class_2", "Girl", "May"]
另外,我想將非法輸入匯總到單獨的 map:
"key7", ["illegal class name", "boy", "err1"]
"key8", ["class_2", "not supported", "err2"]
我試圖分別過濾與每個子圖相關的數據(利用原始代碼中的事實gradeAndClass
和gender
是定義明確的枚舉),但效率非常低。
基本上,我已經對所有條件檢查進行了硬編碼,並且必須按每個gradeAndClass
和gender
進行過濾和重新組合。 我還必須重申每個條目以獲取非法條目,以便將它們放入單獨的“錯誤映射” 。
抱歉,我對流很陌生,所以我知道我的解決方案絕對不可擴展,因此我正在尋找建議。 是否可以使用 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 16record
或class
(或者,很少有快速和骯臟的選項,如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.