我有一个哈希映射,我需要过滤该映射或仅使用给定映射中包含重复值的键创建映射。请建议我们如何实现这一目标?
请注意,给定的输入只是地图。并且没有其他要搜索的值。
Map map = new HashMap();
map.put(1, "abc");
map.put(2, "def");
map.put(3, "mno");
map.put(4, "abc");
map.put(5, "ijk");
map.put(6, "abc");
Map result = new HashMap();
(1, "abc")
(4, "abc")
(6, "abc");
我期待一个包含所有具有重复值的键的新映射
您可以使用流执行此操作。
首先,将条目组合在一起,使具有相同值的条目组合在一起:
Map<String, Map.Entry<Integer, String>> grouped =
map.entrySet().stream()
.collect(groupingBy(Map.Entry::getValue));
然后删除仅出现 1 次值的条目:
grouped.values().removeIf(m -> m.size() <= 1);
然后再次展平条目:
Map<Integer, String> result = grouped.values().stream()
.flatMap(m -> m.entrySet().stream())
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
您也可以在单个表达式中执行此操作:
Map<Integer, String> grouped =
map.entrySet().stream()
.collect(groupingBy(Map.Entry::getValue))
.values().stream()
.filter(m -> m.size() > 1)
.map(Map::entrySet)
.flatMap(Collection::stream)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
您可以创建从值到其频率的映射
Map<V, Long> counts = map.values().stream()
.collect(Collectors.groupingBy(
Function.identity(), Collectors.counting()));
然后过滤原始地图的条目流,保留计数大于 1 的元素,并从中创建新地图:
Map<K, V> result = map.entrySet().stream()
.filter(e -> counts.get(e.getValue()) > 1)
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
下面是一个示例:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
public class RetainFrequentValues
{
public static void main(String[] args)
{
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "abc");
map.put(2, "def");
map.put(3, "mno");
map.put(4, "abc");
map.put(5, "ijk");
map.put(6, "abc");
// For testing
map.put(7, "def");
Map<Integer, String> result = retainFrequentValues(map);
result.entrySet().forEach(System.out::println);
}
private static <K, V> Map<K, V> retainFrequentValues(Map<K, V> map)
{
Map<V, Long> counts = map.values().stream()
.collect(Collectors.groupingBy(
Function.identity(), Collectors.counting()));
Map<K, V> result = map.entrySet().stream()
.filter(e -> counts.get(e.getValue()) > 1)
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
return result;
}
}
利用谷歌的番石榴收藏:
进口:
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Maps;
用法:
Map<Integer, String> map = new HashMap<>();
map.put(1, "abc");
map.put(2, "def");
map.put(3, "mno");
map.put(4, "abc");
map.put(5, "ijk");
map.put(6, "abc");
HashMultiset<String> ms = HashMultiset.create();
ms.addAll(map.values());
ms.removeIf(e -> ms.count(e) == 1);
Map<Integer, String> result = Maps.filterValues(map, ms::contains);
结果:{1=abc, 4=abc, 6=abc}
如果番石榴不是一种选择,请参阅上面的答案之一。