簡體   English   中英

Collectors.groupingBy(函數,供應商,收集器)不接受lambda /不看流式值

[英]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.

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