Java8流/收集器与收集器的映射键。计数()
我想得到由频率键控的数组值频率的映射。 我能够得到相反的地图键的价值。尝试切换参数,但Java8流/收集器与收集器的映射键。计数(),java,java-8,java-stream,Java,Java 8,Java Stream,我想得到由频率键控的数组值频率的映射。 我能够得到相反的地图键的价值。尝试切换参数,但分组依据不接受收集器作为第一个参数 另一个问题是,如何将Map实现更改为LinkedHashMap,以保持按数组元素排序(如果Map由值键控) int[]arr={1,4,5,9,2,4,3,1,1,3,5,3,2,4,2,9,2,1}; Map collect=数组 .stream(arr) .boxed() .collect(Collectors.groupingBy(Function.identity()
分组依据
不接受收集器
作为第一个参数
另一个问题是,如何将Map
实现更改为LinkedHashMap
,以保持按数组元素排序(如果Map由值键控)
int[]arr={1,4,5,9,2,4,3,1,1,3,5,3,2,4,2,9,2,1};
Map collect=数组
.stream(arr)
.boxed()
.collect(Collectors.groupingBy(Function.identity()、Collectors.counting());
结果是{1=4,2=4,3=3,4=3,5=2,9=2}
我要找的是
{4=1,3=[4,3],2=[5,9]…}
这意味着有4次出现1,3次出现4,2次出现5和9
我的目标是以频率作为键,以值作为数组元素的列表来获取Map。对于键冲突,请在值列表中添加另一个值。无流解决方案
Guava附带了一个Multiset
和Multimap
实现,您可以像这样使用它来获得相同的行为:
Multiset<Integer> set = HashMultiset.create();
for (int i : array) {
set.add(i);
}
Multimap<Integer, Integer> byFrequency = HashMultimap.create();
for (Integer key : set.keySet()) {
byFrequency.put(set.count(key), key);
}
Collection<Integer> allKeysWithFreqOfFive = byFrequency.get(5);
Multiset set=HashMultiset.create();
for(int i:array){
增加(i);
}
Multimap byFrequency=HashMultimap.create();
for(整数键:set.keySet()){
按频率输入(设置计数(键),键);
}
收集allKeysWithFreqOfFive=byFrequency.get(5);
一种可能的解决方案是首先创建映射值->频率,然后将其收集到另一个映射中,在该映射中按频率进行分组
Map<Long, List<Integer>> collect =
Arrays.stream(arr)
.boxed()
.collect(collectingAndThen(groupingBy(identity(), counting()),
m -> m.entrySet().stream().collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toList())))));
这是一个测试流API的好问题,因为大多数问题都停留在第一个GROUPBY:GROUPBY元素上。这个问题继续第二组,对我来说很合理。以下是我的一些想法。首先,让我们尝试通过过渡for循环来实现它(虽然这不是OP想要的,但我想稍后比较不同的解决方案) 问题是仍然有一些完全不必要的样板代码掩盖了代码的意图。有一个非常有用的Java 8库可以帮助我们减少样板代码:
零样板代码,完美链条。代码告诉您,并且只告诉您想要什么。示例中的“反向映射”将4映射到1和2。正如您已经知道的,一个键只能映射到一个值,因为如果您再次尝试输入同一个键,该值将被覆盖。所以我不清楚你想要实现什么。试着解释一下你的目标是什么,而不是“如何”实现它(也称为xy问题)。你不能同时拥有
2=5
和2=9
。对不起,我已经更正了我的问题。谢谢,但我对Java流解决方案感兴趣。@joe.d是的,这并不容易,因为没有MultiMap
收集器,因为它在SDK之外,Collectors.toMap()
中的合并功能不够强大,无法实现您想要的功能。@joe.d AlexisC刚刚击败了我;-)雅致的收藏,然后+1.@Alexis C.谢谢!它可以工作,但我们可以保留数组元素的顺序(不是按键排序,而是按数组元素排序)。我想LinkedHashMap会这么做吗?
Map<Long, List<Integer>> collect =
Arrays.stream(arr)
.boxed()
.collect(collectingAndThen(groupingBy(identity(), counting()),
m -> m.entrySet().stream().collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toList())))));
Map<Long, List<Integer>> result = new HashMap<>();
collect.forEach((value, freq) -> result.computeIfAbsent(freq, u -> new ArrayList<>()).add(value));
Map<Integer, Integer> occursMap = new LinkedHashMap<>(); // to keep the order
for (int i : arr) {
occursMap.compute(i, (k, v) -> v == null ? 1 : v + 1);
}
Map<Integer, List<Integer>> res = new HashMap<>();
for (Map.Entry<Integer, Integer> entry : occursMap.entrySet()) {
res.computeIfAbsent(entry.getValue(), k -> new ArrayList<>()).add(entry.getKey());
}
Map<Long, List<Integer>> res = Arrays.stream(arr).boxed()
.collect(collectingAndThen(groupingBy(Function.identity(), LinkedHashMap::new, counting()),
m -> m.entrySet().stream().collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toList())))));
res = Arrays.stream(arr).boxed()
.collect(groupingBy(Function.identity(), LinkedHashMap::new, counting()))
.entrySet().stream().collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toList())));
res = EntryStream.of(
IntStreamEx.of(arr).boxed().groupingBy(Function.identity(), () -> new LinkedHashMap<>(), counting())
).invert().grouping();
res = StreamEx.of(arr).groupByToEntry(Fn.identity(), Fn.countingInt(), LinkedHashMap::new)
.inversed().groupTo();