我有一个如下的哈希图:
1->x
2->y
3->x
4->z
现在我想知道所有值为 x 的键(ans: [1,3] )。最好的方法是什么?
蛮力方法是遍历 map 并将所有键存储在值为 x 的数组中。
有什么有效的方法可以解决这个问题。
谢谢
hashmap 是一种结构,它针对使用键的值的关联访问进行了优化,但在逆向操作方面绝不比数组更好。我不认为你可以做得更好然后只是迭代。提高效率的唯一方法是如果您也有一个反向哈希映射(即哈希映射,您持有一个指向所有值的给定值的键数组)。
您可以使用 aMultiMap
轻松获取所有这些重复值。
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "x");
map.put(2, "y");
map.put(2, "z");
map.put(3, "x");
map.put(4, "y");
map.put(5, "z");
map.put(6, "x");
map.put(7, "y");
System.out.println("Original map: " + map);
Multimap<String, Integer> multiMap = HashMultimap.create();
for (Entry<Integer, String> entry : map.entrySet()) {
multiMap.put(entry.getValue(), entry.getKey());
}
System.out.println();
for (Entry<String, Collection<Integer>> entry : multiMap.asMap().entrySet()) {
System.out.println("Original value: " + entry.getKey() + " was mapped to keys: "
+ entry.getValue());
}
打印出来:
Original map: {1=x, 2=z, 3=x, 4=y, 5=z, 6=x, 7=y}
Original value: z was mapped to keys: [2, 5]
Original value: y was mapped to keys: [4, 7]
Original value: x was mapped to keys: [1, 3, 6]
根据@ noahz的建议,forMap
行invertFrom
数更少,但可以说阅读起来更复杂:
HashMultimap<String, Integer> multiMap =
Multimaps.invertFrom(Multimaps.forMap(map),
HashMultimap.<String, Integer> create());
代替:
Multimap<String, Integer> multiMap = HashMultimap.create();
for (Entry<Integer, String> entry : map.entrySet()) {
multiMap.put(entry.getValue(), entry.getKey());
}
如果 Java 8 是一个选项,您可以尝试流式方法:
Map<Integer, String> map = new HashMap<>();
map.put(1, "x");
map.put(2, "y");
map.put(3, "x");
map.put(4, "z");
Map<String, ArrayList<Integer>> reverseMap = new HashMap<>(
map.entrySet().stream()
.collect(Collectors.groupingBy(Map.Entry::getValue)).values().stream()
.collect(Collectors.toMap(
item -> item.get(0).getValue(),
item -> new ArrayList<>(
item.stream()
.map(Map.Entry::getKey)
.collect(Collectors.toList())
))
));
System.out.println(reverseMap);
结果是:
{x=[1, 3], y=[2], z=[4]}
如果首选 Java 7:
Map<String, ArrayList<Integer>> reverseMap = new HashMap<>();
for (Map.Entry<Integer,String> entry : map.entrySet()) {
if (!reverseMap.containsKey(entry.getValue())) {
reverseMap.put(entry.getValue(), new ArrayList<>());
}
ArrayList<Integer> keys = reverseMap.get(entry.getValue());
keys.add(entry.getKey());
reverseMap.put(entry.getValue(), keys);
}
有趣的是,在执行 (index,random('a'-'z') 对的大型映射时,我尝试了每种算法所需的时间。
10,000,000 20,000,000
Java 7: 615 ms 11624 ms
Java 8: 1579 ms 2176 ms
如果您愿意使用图书馆,请使用Google Guava 的 Multimaps 实用程序,特别是forMap()
与invertFrom()
是的,只是蛮力。您还可以通过从 Value -> Collection of Key 存储 Multimap 来加快速度,但代价是内存和运行时更新成本。
HashMap
计算hashcode()
键的,而不是值的。除非您存储某种附加信息,或考虑使用不同的数据结构,否则我认为获得此信息的唯一方法是蛮力。
如果您需要对值执行有效的操作,您应该考虑是否使用了适当的数据结构。
如果您已经有地图,您应该考虑使用Google 的 Guava库来过滤您感兴趣的条目。您可以按照以下方式进行操作:
final Map<Integer, Character> filtered = Maps.filterValues(unfiltered, new Predicate<Character>() {
@Override
public boolean apply(Character ch) {
return ch == 'x';
}
});
如果您使用的是哈希图,则没有有效的方法可以做到这一点,而是迭代值
我同意 George Campbell 的观点,但对于 java 8,我会更容易一些:
Map<String, List<Integer>> reverseMap = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue,
Collectors.mapping(
Map.Entry::getKey,
Collectors.toList())));
尝试这个.....
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("cust_tenure", "3_sigma");
hashMap.put("cust_age", "3_sigma");
hashMap.put("cust_amb_6m_sav", "3_sigma");
hashMap.put("cust_amb_6m_chq", "3_sigma");
hashMap.put("cust_total_prod_6m", "3_sigma");
HashMap<String, ArrayList<String>> result = new LinkedHashMap<String, ArrayList<String>>();
for (String key : hashMap.keySet()) {
ArrayList<String> colName = null;
if (!result.containsKey(hashMap.get(key))) {
colName = new ArrayList<String>();
colName.add(key);
result.put(hashMap.get(key), colName);
} else {
colName = result.get(hashMap.get(key));
colName.add(key);
result.put(hashMap.get(key), colName);
}
System.out.println(key + "\t" + hashMap.get(key));
}
for (String key : result.keySet()) {
System.out.println(key + "\t" + result.get(key));
}
System.out.println(hashMap.size());
}