Inverted Collectors.toMap添加到ArrayList

Joh*_*ess 6 java java-8 java-stream collectors

我想把数字的频率放在一个TreeMap频率为频率的频率和频率为a 的数字中ArrayList.

我有两个问题:

1)我在第一个参数中得到"非静态方法无法从静态上下文引用"错误(AFAIK流引用一个对象 - 发生了什么?)

2)Collectors.toMap()有4个参数 - 看起来参数4需要使用新的TreeMap进行初始化>,参数2可以是ArrayList add()函数,参数3可以是null(可能).这是怎么做到的?

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {

        List<Integer> array = Arrays.asList(1, 2, 4, 5, 6, 4, 8, 4, 2, 3);

        Map<Integer, Long> m = array.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        System.out.println(m);

        TreeMap<Long, List<Integer>> tm = m.entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getValue, ...));
Run Code Online (Sandbox Code Playgroud)

目前我无法使用如何从 https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html到我需要的地方.

Fed*_*ner 7

我不会使用流来创建倒置的地图.相反,我会这样做:

Map<Long, List<Integer>> tm = new TreeMap<>();
m.forEach((num, freq) -> tm.computeIfAbsent(freq, k -> new ArrayList<>()).add(num));

System.out.println(tm); // {1=[1, 3, 5, 6, 8], 2=[2], 3=[4]}
Run Code Online (Sandbox Code Playgroud)

由于创建倒置贴图的代码很短,您可以使用Collectors.collectingAndThen一步创建频率和倒置贴图:

TreeMap<Long, List<Integer>> invertedFrequenciesMap = array.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.groupingBy(Function.identity(), Collectors.counting()),
        map -> {
            TreeMap<Long, List<Integer>> tm = new TreeMap<>();
            map.forEach((num, freq) ->
                    tm.computeIfAbsent(freq, k -> new ArrayList<>()).add(num));
            return tm;
        }));
Run Code Online (Sandbox Code Playgroud)

  • 肯定是+1(最初要显示相同的东西,但是OP询问如何处理`toMap` ...) (2认同)

Eug*_*ene 6

你的推理几乎是正确的......只是第3个参数是你为同一个键合并你的值的地方 - 所以你不能省略它.

 TreeMap<Long, List<Integer>> tm = m.entrySet().stream()
            .collect(Collectors.toMap(
                  Entry::getValue, 
                  x -> {
                      List<Integer> list = new ArrayList<>();
                      list.add(x.getKey());
                      return list;
                  }, 
                  (left, right) -> {
                     left.addAll(right);
                     return left;
                  }, 
                  TreeMap::new));
Run Code Online (Sandbox Code Playgroud)


Era*_*ran 6

我觉得Collectors.groupingByCollectors.toMap实现你想要的更有意义:

Map<Long, List<Integer>> tm = 
    m.entrySet()
     .stream()
     .collect(Collectors.groupingBy(Map.Entry::getValue, // group the entries by the 
                                                         // value (the frequency)
                                    TreeMap::new, // generate a TreeMap
                                    Collectors.mapping (Map.Entry::getKey, 
                                                        Collectors.toList()))); // the
                                                         // value of the output TreeMap 
                                                         // should be a List of the 
                                                         // original keys
Run Code Online (Sandbox Code Playgroud)

您可以替换Collectors.toList()使用Collectors.toCollection(ArrayList::new),以确保输出的值MapArrayListS(虽然目前执行的toList()已经导致java.util.ArrayList实例).

对于您的示例输入,这会产生以下结果TreeMap:

{1=[1, 3, 5, 6, 8], 2=[2], 3=[4]}
Run Code Online (Sandbox Code Playgroud)