Java:如何在hashmap中获取具有相同值的键集
我有一个hashmap如下:
1-> X
2->ÿ
3-> X
4->ž
现在我想知道值为x的所有键(ans:[1,3])。 什么是最好的方法?
蛮力方式是迭代地图并将所有键存储在值为x的数组中。
有没有有效的方法。
谢谢
您可以使用MultiMap
轻松获取所有这些重复值。
Map map = new HashMap(); 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 multiMap = HashMultimap.create(); for (Entry entry : map.entrySet()) { multiMap.put(entry.getValue(), entry.getKey()); } System.out.println(); for (Entry> 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 multiMap = Multimaps.invertFrom(Multimaps.forMap(map), HashMultimap. create());
取代:
Multimap multiMap = HashMultimap.create(); for (Entry entry : map.entrySet()) { multiMap.put(entry.getValue(), entry.getKey()); }
散列映射是一种优化的结构,用于使用键对值进行关联访问,但在执行反向操作时却没有比使用数组更好的结构。 我不认为你可以做得更好,然后迭代。 提高效率的唯一方法是,如果您也有反向哈希映射(即哈希映射,其中您持有指向所有值的给定值的键数组)。
如果Java 8是一个选项,您可以尝试流式处理方法:
Map map = new HashMap<>(); map.put(1, "x"); map.put(2, "y"); map.put(3, "x"); map.put(4, "z"); Map> 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> reverseMap = new HashMap<>(); for (Map.Entry entry : map.entrySet()) { if (!reverseMap.containsKey(entry.getValue())) { reverseMap.put(entry.getValue(), new ArrayList<>()); } ArrayList keys = reverseMap.get(entry.getValue()); keys.add(entry.getKey()); reverseMap.put(entry.getValue(), keys); }
有趣的是,我在执行(索引,随机(’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 – > Key of Key的Multimap来加快速度,但代价是更新的内存和运行时成本。
HashMap
计算键的hashcode()
,而不是值。 除非您存储某种附加信息,或考虑使用不同的数据结构,否则我认为唯一可以获得此信息的方法就是蛮力。
如果需要对值执行高效操作,则应考虑是否使用了适当的数据结构。
如果您使用的是散列映射,那么除了迭代值之外没有有效的方法
如果您已有地图,则应考虑使用Google的Guava库来过滤您感兴趣的条目。您可以执行以下操作:
final Map filtered = Maps.filterValues(unfiltered, new Predicate() { @Override public boolean apply(Character ch) { return ch == 'x'; } });
我同意George Campbell但是对于java 8我会更容易做到:
Map> reverseMap = map.entrySet() .stream() .collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping( Map.Entry::getKey, Collectors.toList())));
尝试这个…..
public static void main(String[] args) { HashMap hashMap = new HashMap(); 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> result = new LinkedHashMap>(); for (String key : hashMap.keySet()) { ArrayList colName = null; if (!result.containsKey(hashMap.get(key))) { colName = new ArrayList (); 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()); }