我使用groupingBy
,mapping
和reducing
以下問題的解決方案發揮各地:Elegantly create map with object fields as key/value from object stream in Java 8。總結的目的是爲了獲得與年齡鍵和一個人作爲Set
的愛好的地圖。的Java 8 stream.collect(... groupingBy(...映射(...還原)))減少BinaryOperator使用率
一個我想出瞭解決方案(不是很好,但是這不是重點),有一個奇怪的行爲。
用下面的列表作爲輸入:
List<Person> personList = Arrays.asList(
new Person(/* name */ "A", /* age */ 23, /* hobbies */ asList("a")),
new Person("BC", 24, asList("b", "c")),
new Person("D", 23, asList("d")),
new Person("E", 23, asList("e"))
);
及以下解決方案:
Collector<List<String>, ?, Set<String>> listToSetReducer = Collectors.reducing(new HashSet<>(), HashSet::new, (strings, strings2) -> {
strings.addAll(strings2);
return strings;
});
Map<Integer, Set<String>> map = personList.stream()
.collect(Collectors.groupingBy(o -> o.age,
Collectors.mapping(o -> o.hobbies, listToSetReducer)));
System.out.println("map = " + map);
我:
map = {23=[a, b, c, d, e], 24=[a, b, c, d, e]}
顯然不是我所期待的。我寧願預計:
map = {23=[a, d, e], 24=[b, c]}
現在,如果我只是取代的二元運算(strings, strings2)
的順序(降低集電極),以(strings2, strings)
我得到預期的結果。那麼我在這裏錯過了什麼? 我有沒有曲解reducing
-collector?或者我錯過了哪些文檔,很明顯我的使用不能按預期工作?
Java版本是1.8.0_121如果該事項。
有趣..起初,我甚至試圖找到'flatMapping'在'Collectors'(或申請'hobbies.stream()',並與它的工作) 。很高興知道它即將到來。哦,親愛的,我把混合器與操作員混在一起。所以,只有切換參數纔是正確的結果。感謝您的澄清! – Roland
是的,在順序上下文中,縮減函數總是被評估爲'f(previous,next)',而'previous'將是第一次評估的身份值和後續評估的先前結果。因此'(a,b) - > a'將始終以標識值結束,而'(a,b) - > b'將使用映射器函數創建的新集。但在並行評估中,兩個參數都可能是之前部分評估的結果,而且由於部分結果可能爲空,因此任一參數都可能是標識值,因此使用第二個參數不是可靠的修補程序。 – Holger