[英]Custom Collector for Collectors.groupingBy doesn't work as expected
[英]Collectors.groupingBy (Function, Supplier, Collector) doesn't accept lambda / dosen't see streamed values
我嘗試使用流和收集器對值進行分組。 我有我必須拆分的字符串列表。
我的數據:
List<String> stringList = new ArrayList<>();
stringList.add("Key:1,2,3")
stringList.add("Key:5,6,7")
鍵是地圖中的鍵, 1,2,3是地圖中的值
首先我嘗試使用簡單的toMap
Map<String, List<Integer>> outputKeyMap = stringList.stream()
.collect(Collectors.toMap(id -> id.split(":")[0],
id-> Arrays.stream(id.split(":")[1].split(",")).collect(Collectors.toList());
但它不起作用,因為它總是創造相同的鍵。 所以我需要使用groupingBy
函數。
Map<String, List<Integer>> outputKeyMap = stringList.stream().collect(groupingBy(id -> id.toString().split(":")[0],
TreeMap::new,
Collectors.mapping(id-> Arrays.stream(id.toString().split(":")[1].split(","))
.map(Integer::valueOf)
.collect(Collectors.toSet()))));
但是在這個解決方案中,編譯器看不到傳遞給lambda函數的值,我不知道為什么因為Function
是第一個參數,也是到了Collectors.mapping
。 在此解決方案流中不起作用。
Collectors.groupingBy (Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream)
編輯:為什么groupingBy函數不起作用
我忘了在Collectors.mapping中添加Collectors.toSet()作為第二個參數。 但后來我收到了Set in Set,所以這不是我要找的東西。 應該使用flatMapping但它在Java9中。
Map<String, Set<Set<String>>> collect = stringList.stream()
.collect(groupingBy(id -> id.split(":")[0],
TreeMap::new,
Collectors.mapping(id-> Arrays.stream(id.toString().split(":")[1].split(","),
Collectors.toSet())
您必須使用接受合並函數的Collectors.toMap
的重載:
Map<String, List<Integer>> result = stringList.stream()
.map(string -> string.split(":"))
.collect(Collectors.toMap(
splitted -> splitted[0],
splitted -> Arrays.stream(splitted[1].split(","))
.map(Integer::valueOf)
.collect(Collectors.toCollection(ArrayList::new)),
(l1, l2) -> { l1.addAll(l2); return l1; }));
這里(l1, l2) -> { l1.addAll(l2); return l1; }
(l1, l2) -> { l1.addAll(l2); return l1; }
(l1, l2) -> { l1.addAll(l2); return l1; }
是合並功能。 只要存在密鑰沖突,收集器就會調用它。 當List.addAll
改變列表時,我們需要確保創建的第一個列表是可變的,因此在值映射器函數中使用.collect(Collectors.toCollection(ArrayList::new))
。
我還優化了第一次拆分到收集前調用的Stream.map
操作,從而避免了多次拆分。
上述解決方案不會從列表中刪除重復項。 如果你需要,你應該收集到一個Set
:
Map<String, Set<Integer>> result = stringList.stream()
.map(string -> string.split(":"))
.collect(Collectors.toMap(
splitted -> splitted[0],
splitted -> Arrays.stream(splitted[1].split(","))
.map(Integer::valueOf)
.collect(Collectors.toCollection(LinkedHashSet::new)),
(s1, s2) -> { s1.addAll(s2); return s1; }));
請注意, LinkedHashSet
保留了插入順序。
假設您的源列表中沒有重復的鍵,您可以獲得Map<String, List<Integer>>
如:
Map<String, List<Integer>> result = stringList.stream()
.collect(toMap(string -> string.split(":")[0],
string -> Arrays.stream(string.split(":")[1].split(","))
.map(Integer::valueOf)
.collect(toList())));
如果你有重復的鍵,有一種方法可以使用flatMapping
的flatMapping:
Map<String, List<Integer>> result = stringList.stream()
.collect(groupingBy(s -> s.split(":")[0],
flatMapping(s -> Arrays.stream(s.split(":")[1].split(","))
.map(Integer::valueOf),
toList())));
輸出將包含Key
所有整數值:
{Key=[1, 2, 3, 5, 6, 7]}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.