反转 Collectors.toMap 以添加到 ArrayList
Inverted Collectors.toMap to add to an ArrayList
我想将数字的频率放在 TreeMap
中,以频率作为键,将具有该频率的数字放在 ArrayList
中。
我有两个问题:
1) 我在第一个参数中收到 "non-static methods cannot be referenced from a static context" 错误(据我所知,流引用了一个对象 - 发生了什么事?)
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, ...));
目前我无法使用查看如何从
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html 到我需要去的地方。
您的推理几乎是正确的...只是第三个参数是您合并同一个键的值的地方 - 所以您不能省略它。
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));
我认为 Collectors.groupingBy
比 Collectors.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
您可以将 Collectors.toList()
替换为 Collectors.toCollection(ArrayList::new)
以确保输出 Map
的值是 ArrayList
s(尽管 [=18= 的当前实现] 已经导致 java.util.ArrayList
个实例)。
对于您的样本输入,这会产生以下 TreeMap
:
{1=[1, 3, 5, 6, 8], 2=[2], 3=[4]}
我不会使用流来创建倒置地图。相反,我会这样做:
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]}
由于创建倒置图的代码很短,您可以使用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;
}));
我想将数字的频率放在 TreeMap
中,以频率作为键,将具有该频率的数字放在 ArrayList
中。
我有两个问题:
1) 我在第一个参数中收到 "non-static methods cannot be referenced from a static context" 错误(据我所知,流引用了一个对象 - 发生了什么事?)
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, ...));
目前我无法使用查看如何从 https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html 到我需要去的地方。
您的推理几乎是正确的...只是第三个参数是您合并同一个键的值的地方 - 所以您不能省略它。
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));
我认为 Collectors.groupingBy
比 Collectors.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
您可以将 Collectors.toList()
替换为 Collectors.toCollection(ArrayList::new)
以确保输出 Map
的值是 ArrayList
s(尽管 [=18= 的当前实现] 已经导致 java.util.ArrayList
个实例)。
对于您的样本输入,这会产生以下 TreeMap
:
{1=[1, 3, 5, 6, 8], 2=[2], 3=[4]}
我不会使用流来创建倒置地图。相反,我会这样做:
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]}
由于创建倒置图的代码很短,您可以使用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;
}));