2 回答

TA貢獻1775條經驗 獲得超8個贊
你在這里遇到困難有點令人驚訝,因為你已經展示了所有必要事物的知識。您知道groupingBy可以取另一個Collector,您toMap已經命名了正確的,并且您已經使用函數來提取Map.Entry值。
結合這些東西,給你
Map<Long, Map<Integer, Long>> groups = filtered.entrySet().stream()
.collect(Collectors.groupingBy(x -> x.getValue(),
Collectors.toMap(x -> x.getKey(), x -> x.getValue())));
System.out.println("grouped " + groups);
為了更好地演示操作,我將輸入更改為
List<Integer> list = Arrays.asList(1, 1, 1, 2, 3, 3, 3, 3, 4, 4, 4);
這導致
grouped {3=[1=3, 4=3], 4=[3=4]}
但是,重復始終與外部映射鍵相同的計數是沒有意義的。所以另一種選擇是
Map<Long, List<Integer>> groups = filtered.entrySet().stream()
.collect(Collectors.groupingBy(Map.Entry::getValue,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
System.out.println("grouped " + groups);
這導致
grouped {3=[1, 4], 4=[3]}
請注意,您不應將forEach/forEachOrdered用于put映射。您的中間步驟應該是
//Sort desc
Map<Integer, Long> descendingSorted = countGrouped.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(a,b) -> { throw new AssertionError(); }, LinkedHashMap::new));
System.out.println("sorted " + descendingSorted);
//filter
Map<Integer, Long> filtered = descendingSorted.entrySet().stream()
.filter(x -> x.getValue() >= 2)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(a,b) -> { throw new AssertionError(); }, LinkedHashMap::new));
System.out.println("filtered " + filtered);
接受地圖工廠的toMap收集器迫使我們提供合并功能,但由于我們的輸入已經是一個必須具有不同鍵的地圖,我在這里提供了一個始終拋出的功能,因為如果出現重復項,就會出現嚴重錯誤。
但請注意,強制所有這些操作收集到新地圖中是不必要的復雜和低效的。首先對整個數據進行排序并filter隨后減少數據量也沒有意義。首先過濾可能會減少排序步驟的工作,而過濾操作的結果不應取決于順序。
在單個管道中完成整個操作要好得多
List<Integer> list = Arrays.asList(1, 1, 1, 2, 3, 3, 3, 3, 4, 4, 4);
Map<Integer, Long> countGrouped = list.stream().collect(
Collectors.groupingBy(x -> x, Collectors.counting()));
System.out.println("group by value, count " + countGrouped);
Map<Long, List<Integer>> groups = countGrouped.entrySet().stream()
.filter(x -> x.getValue() >= 2)
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.groupingBy(Map.Entry::getValue, LinkedHashMap::new,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
System.out.println("grouped " + groups);
請注意,與之前的代碼不同,現在最后的分組操作也會保留順序,從而導致
grouped {4=[3], 3=[1, 4]}
即,組按計數降序排序。
由于計數是結果映射的鍵,我們還可以使用本質上排序的映射作為結果類型并省略排序步驟:
Map<Long, List<Integer>> groups = countGrouped.entrySet().stream()
.filter(x -> x.getValue() >= 2)
.collect(Collectors.groupingBy(Map.Entry::getValue,
() -> new TreeMap<>(Comparator.<Long>reverseOrder()),
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
主要區別在于流操作后結果映射的行為,例如,如果您向其中插入更多元素,因為TreeMap將根據降序插入新鍵,而LinkedHashMap將它們追加到末尾,保持插入順序。

TA貢獻1963條經驗 獲得超6個贊
的簽名groupingBy是public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier),但如果我理解正確,您只想將值映射到地圖條目,例如:
Map<Object, Map.Entry<Integer, Long>> groups = filtered.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getValue, x -> x));
System.out.println("grouped " + groups);
輸出
grouped {3=1=3, 4=3=4}
添加回答
舉報