我有一个哈希图,我知道有些键映射到相同的值 这些键的数量非常小(小于6%),它们映射在2-4个值之间 例如。
Map<String, String> map = new HashMap<>();
map.put("codeA", "100");
map.put("codeB", "7");
map.put("codeC", "0012");
我需要从值到键创建此映射的反转,所以我做了:
inverseMap = new HashMap<String, ArrayList<String>>();
for(Map.Entry<String, String> e:map.entrySet()) {
String code = e.getKey();
String val = e.getValue();
ArrayList<String> codesColliding = inverseMap.get(val);
if(codesColliding == null) {
codesColliding = new ArrayList<>(4);
inverseMap.put(val, codesColliding);
}
codesColliding.add(code);
}
这有效,但我认为它不是最理想的,因为我使用的内存超过绝大多数键所需的内存。
虽然从编码的角度看它是有效的,但我想知道这是否可以采用不同的方式(通过其他数据结构?)
注意:我对普通的Java 7(没有额外的库)方法感兴趣
答案 0 :(得分:2)
如果逆映射的值需要能够容纳来自原始映射的多个键,那么相对于它们不需要如此容纳的情况,没有避免一些开销。你当前的方法并不差,但是如果原始地图的价值的这么小的一部分是重复的,并且没有重复超过几次,那么我对你使用的列表的初始容量更加吝啬作为逆映射中的值。为什么预分配任何多个元素?您很少需要重新分配,但是当您这样做时,列表将透明地处理它。
答案 1 :(得分:0)
也许最简单的方法是创建一个具有两个HashMaps的类,一个用于非碰撞键,另一个用于碰撞的键。如果以某种方式消除碰撞的歧义(例如,您总是按字母顺序选择第一个),则可以将该逻辑添加到类中。或者,如果要返回ArrayLists,可以懒惰地将非碰撞字符串包装到ArrayList中。
这一切都是为了知道你想要用Map做什么。如果您确信您的代码可以处理String和ArrayList结果之间的歧义,您甚至可以牺牲一些类型的安全性。
答案 2 :(得分:0)
我知道你在谈论Map<String,String>
,但为了清楚起见,我们将其概括为Map<K,V>
,您正在构建Map<V,Collection<K>>
。添加另一个Map<V,K>
,也许称之为uniqueInverseMap
。在浏览条目时,请务必先在inverseMap
,然后uniqueInverseMap
中检查密钥。如果它已经在uniqueInverseMap
中,请将其删除,创建一个新的双元素列表,将列表添加到inverseMap
。