在 Multimap 中如何 return 出现次数最多的值
In Multimap how to return value which has highest occurrence
我有来自 guava 库的 MultiMap
Multimap<Integer,String> maps = ArrayListMultimap.create();
maps.put(1, "foo");
maps.put(1, "bar");
maps.put(1, "foo");
maps.put(2, "Hello");
maps.put(2, "foo");
maps.put(2, "World");
maps.put(2, "World");
在此对于键 1,我需要 return 出现次数最多的值。在上面的例子中,它必须 return 映射为
预期结果:
[1,foo]
[2,World]
我试过了
Stream result1 = maps.keySet().stream()
.map(i ->
maps.get(i).stream()
.collect(
Collectors.groupingBy(v -> v, Collectors.counting())
)
);
结果:
{{bar=1, foo=2}=1, {Hello=1, foo=1, World=2}=1}
您似乎正在寻找的东西可以在迭代条目时实现:
Map<Integer, String> integerStringMap = maps.asMap()
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey,
e -> mostFrequentWord(e.getValue())));
mostFrequentWord
的实现应该return一个String
如:
static String mostFrequentWord(Collection<String> values) {
return values.stream()
.collect(Collectors.groupingBy(v -> v, Collectors.counting()))
.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElseThrow(() -> new UnsupportedOperationException(
"Empty collection as values in multimap"));
}
maps.keySet().stream().distinct().collect(Collectors.toMap(key -> key, key -> {
Map<String, Long> valueByCount = maps.get(key).stream().collect(Collectors.groupingBy(s -> s, Collectors.counting()));
return valueByCount.entrySet()
.stream()
.max(Comparator.comparing(Map.Entry::getValue))
.map(Map.Entry::getKey)
.orElse(null);
}));
你可以这样做:
var valueFrequency = maps.entries().stream()
.collect(groupingBy(Function.identity(), counting()));
var result = valueFrequency.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.stream()
.flatMap(maxFreq -> valueFrequency.entrySet().stream()
.filter(val -> val.getValue().equals(maxFreq.getValue()))
.map(Map.Entry::getKey))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
这不会非常直截了当。显然,您首先需要按键分组。然后基于 Key
,您需要找到相应 Value
的最大出现次数(例如 1 == foo
)。找到max
的唯一方法是遍历映射到某个键的Collection<String>
。这使事情变得更加复杂,因为您使用 Multimap
并且您可以轻松地拥有以下内容:
maps.put(1, "foo");
maps.put(1, "bar");
maps.put(1, "bar");
maps.put(1, "foo");
因此,IMO,这可以写成:
Map<Integer, List<String>> result =
maps.keySet()
.stream()
.collect(Collectors.toMap(
Function.identity(),
x -> {
Map<String, Long> freqMap = maps.get(x)
.stream()
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting())
);
long max = Collections.max(freqMap.values());
return freqMap.entrySet()
.stream()
.filter(y -> y.getValue() == max)
.map(Entry::getKey)
.collect(Collectors.toList());
}
));
- 我先按
Key
(1
和 2
)分组
- 然后获取映射到该 Key
的 Collection<String>
- 然后计算表示值频率的
Map<String, Long>
。例如:["foo" = 2]; ["bar" = 1]
- 然后我查看最大出现次数。由于您使用的是多图,对于相同的
Key
,您可能会遇到 ["foo" = 2]; ["bar" = 2]
的情况,因此我们需要将 foo
和 bar
作为结果。
- 基于那个
max
,我找出了相应的值。
没有流,但使用 Guava 之类的东西 Multiset
and Maps.transformValues
:
@Test
public void shouldFindHightestOccurrencesInMultimapValues() {
//given
Multimap<Integer, String> maps = ArrayListMultimap.create();
maps.put(1, "foo");
maps.put(1, "bar");
maps.put(1, "foo");
maps.put(2, "Hello");
maps.put(2, "foo");
maps.put(2, "World");
maps.put(2, "World");
//when
Map<Integer, String> result = ImmutableMap.copyOf(Maps.transformValues(maps.asMap(), this::findHighestOccurrence));
//then
assertThat(result).containsOnly(
entry(1, "foo"),
entry(2, "World"));
}
private String findHighestOccurrence(Collection<String> values) {
return Multisets.copyHighestCountFirst(ImmutableMultiset.copyOf(values)).iterator().next();
}
如果有一个 MultisetMultimap 子类型(即 Map<K, Multiset<V>>
-like specialized Multimap
,在这种情况下它可能是存储数据的最佳结构。
我有来自 guava 库的 MultiMap
Multimap<Integer,String> maps = ArrayListMultimap.create();
maps.put(1, "foo");
maps.put(1, "bar");
maps.put(1, "foo");
maps.put(2, "Hello");
maps.put(2, "foo");
maps.put(2, "World");
maps.put(2, "World");
在此对于键 1,我需要 return 出现次数最多的值。在上面的例子中,它必须 return 映射为
预期结果:
[1,foo]
[2,World]
我试过了
Stream result1 = maps.keySet().stream()
.map(i ->
maps.get(i).stream()
.collect(
Collectors.groupingBy(v -> v, Collectors.counting())
)
);
结果:
{{bar=1, foo=2}=1, {Hello=1, foo=1, World=2}=1}
您似乎正在寻找的东西可以在迭代条目时实现:
Map<Integer, String> integerStringMap = maps.asMap()
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey,
e -> mostFrequentWord(e.getValue())));
mostFrequentWord
的实现应该return一个String
如:
static String mostFrequentWord(Collection<String> values) {
return values.stream()
.collect(Collectors.groupingBy(v -> v, Collectors.counting()))
.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElseThrow(() -> new UnsupportedOperationException(
"Empty collection as values in multimap"));
}
maps.keySet().stream().distinct().collect(Collectors.toMap(key -> key, key -> {
Map<String, Long> valueByCount = maps.get(key).stream().collect(Collectors.groupingBy(s -> s, Collectors.counting()));
return valueByCount.entrySet()
.stream()
.max(Comparator.comparing(Map.Entry::getValue))
.map(Map.Entry::getKey)
.orElse(null);
}));
你可以这样做:
var valueFrequency = maps.entries().stream()
.collect(groupingBy(Function.identity(), counting()));
var result = valueFrequency.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.stream()
.flatMap(maxFreq -> valueFrequency.entrySet().stream()
.filter(val -> val.getValue().equals(maxFreq.getValue()))
.map(Map.Entry::getKey))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
这不会非常直截了当。显然,您首先需要按键分组。然后基于 Key
,您需要找到相应 Value
的最大出现次数(例如 1 == foo
)。找到max
的唯一方法是遍历映射到某个键的Collection<String>
。这使事情变得更加复杂,因为您使用 Multimap
并且您可以轻松地拥有以下内容:
maps.put(1, "foo");
maps.put(1, "bar");
maps.put(1, "bar");
maps.put(1, "foo");
因此,IMO,这可以写成:
Map<Integer, List<String>> result =
maps.keySet()
.stream()
.collect(Collectors.toMap(
Function.identity(),
x -> {
Map<String, Long> freqMap = maps.get(x)
.stream()
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting())
);
long max = Collections.max(freqMap.values());
return freqMap.entrySet()
.stream()
.filter(y -> y.getValue() == max)
.map(Entry::getKey)
.collect(Collectors.toList());
}
));
- 我先按
Key
(1
和2
)分组 - 然后获取映射到该 Key 的
- 然后计算表示值频率的
Map<String, Long>
。例如:["foo" = 2]; ["bar" = 1]
- 然后我查看最大出现次数。由于您使用的是多图,对于相同的
Key
,您可能会遇到["foo" = 2]; ["bar" = 2]
的情况,因此我们需要将foo
和bar
作为结果。 - 基于那个
max
,我找出了相应的值。
Collection<String>
没有流,但使用 Guava 之类的东西 Multiset
and Maps.transformValues
:
@Test
public void shouldFindHightestOccurrencesInMultimapValues() {
//given
Multimap<Integer, String> maps = ArrayListMultimap.create();
maps.put(1, "foo");
maps.put(1, "bar");
maps.put(1, "foo");
maps.put(2, "Hello");
maps.put(2, "foo");
maps.put(2, "World");
maps.put(2, "World");
//when
Map<Integer, String> result = ImmutableMap.copyOf(Maps.transformValues(maps.asMap(), this::findHighestOccurrence));
//then
assertThat(result).containsOnly(
entry(1, "foo"),
entry(2, "World"));
}
private String findHighestOccurrence(Collection<String> values) {
return Multisets.copyHighestCountFirst(ImmutableMultiset.copyOf(values)).iterator().next();
}
如果有一个 MultisetMultimap 子类型(即 Map<K, Multiset<V>>
-like specialized Multimap
,在这种情况下它可能是存储数据的最佳结构。