使用重复键映射实现
我想拥有带有重复键的Map,我知道有很多Map的实现(日食显示了我约50),所以我敢打赌,必须有一个允许这个。 我知道它很容易编写自己的地图,但我宁愿使用一些现有的解决scheme。 也许有一些共同点 – collections或谷歌collections?
你正在寻找一个multimap,事实上commons-collections和Guava都有几个实现。 多图可以通过维护每个键的值的集合来允许多个键,即,可以将单个对象放入地图中,但是您可以检索集合。
如果你可以使用Java 5,我更喜欢Guava的Multimap
因为它是generics意识。
我们不需要依赖Google Collections外部库。 你可以简单地实现下面的地图:
Map<String, ArrayList<String>> hashMap = new HashMap<String, ArrayList>(); public static void main(String... arg) { // Add data with duplicate keys addValues("A", "a1"); addValues("A", "a2"); addValues("B", "b"); // View data. Iterator it = hashMap.keySet().iterator(); ArrayList tempList = null; while (it.hasNext()) { String key = it.next().toString(); tempList = hashMap.get(key); if (tempList != null) { for (String value: tempList) { System.out.println("Key : "+key+ " , Value : "+value); } } } } private void addValues(String key, String value) { ArrayList tempList = null; if (hashMap.containsKey(key)) { tempList = hashMap.get(key); if(tempList == null) tempList = new ArrayList(); tempList.add(value); } else { tempList = new ArrayList(); tempList.add(value); } hashMap.put(key,tempList); }
请确保微调代码。
您可以简单地在常规的HashMap中传递值的数组,这样就可以模拟重复的键,这取决于您决定使用哪些数据。
你也可以使用一个MultiMap ,尽pipe我不喜欢自己的重复键的想法。
Multimap<Integer, String> multimap = ArrayListMultimap.create(); multimap.put(1, "A"); multimap.put(1, "B"); multimap.put(1, "C"); multimap.put(1, "A"); multimap.put(2, "A"); multimap.put(2, "B"); multimap.put(2, "C"); multimap.put(3, "A"); System.out.println(multimap.get(1)); System.out.println(multimap.get(2)); System.out.println(multimap.get(3));
输出是:
[A,B,C,A] [A,B,C] [A]
注意:我们需要导入库文件。
http://www.java2s.com/Code/Jar/g/Downloadgooglecollectionsjar.htm
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap;
或https://commons.apache.org/proper/commons-collections/download_collections.cgi
import org.apache.commons.collections.MultiMap; import org.apache.commons.collections.map.MultiValueMap;
如果你想迭代关键值对的列表(就像你在注释中写的那样),那么List或数组应该更好。 首先结合您的键和值:
public class Pair { public Class1 key; public Class2 value; public Pair(Class1 key, Class2 value) { this.key = key; this.value = value; } }
将Class1和Class2replace为要用于键和值的types。
现在你可以把它们放入一个数组或者一个列表中,并遍历它们:
Pair[] pairs = new Pair[10]; ... for (Pair pair : pairs) { ... }
commons.apache.org MultiValueMap class
从我的错误中学习…请不要自行实施。 番石榴multimap是要走的路。
multimaps中所需的常见增强function是禁止重复的键值对。
在你的实现中实现/改变它可能会很烦人。
在番石榴其简单如:
HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create(); ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();
这个问题可以用映射条目List<Map.Entry<K,V>>
。 我们不需要使用外部库,也不需要新的Map实现。 映射条目可以这样创build: Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);
我有一个稍微不同的这个问题的变体:它需要关联两个不同的值与相同的密钥。 只要在这里发布它,以帮助其他人,我已经引入了一个HashMap作为值:
/* @param frameTypeHash: Key -> Integer (frameID), Value -> HashMap (innerMap) @param innerMap: Key -> String (extIP), Value -> String If the key exists, retrieve the stored HashMap innerMap and put the constructed key, value pair */ if (frameTypeHash.containsKey(frameID)){ //Key exists, add the key/value to innerHashMap HashMap innerMap = (HashMap)frameTypeHash.get(frameID); innerMap.put(extIP, connName+":"+frameType+":"+interfaceName); } else { HashMap<String, String> innerMap = new HashMap<String, String>(); innerMap.put(extIP, connName+":"+frameType+":"+interfaceName); // This means the key doesn't exists, adding it for the first time frameTypeHash.put(frameID, innerMap ); } }
在上面的代码中,每个行的input文件的第一个string中读取了关键的frameID,frameTypeHash的值是通过拆分剩下的行来构造的,并且最初被存储为String对象,在一段时间内文件开始有多行与不同的值)关联相同的frameID键,所以frameTypeHash被覆盖最后一行作为值。 我将String对象replace为另一个HashMap对象作为值字段,这有助于保持单键到不同的值映射。
如果有重复的键,那么一个键可以对应多个值。 显而易见的解决scheme是将键映射到这些值的列表。
例如在Python中:
map = dict() map["driver"] = list() map["driver"].append("john") map["driver"].append("mike") print map["driver"] # It shows john and mike print map["driver"][0] # It shows john print map["driver"][1] # It shows mike
你能不能解释一下你试图用重复键实现地图的上下文? 我相信可以有更好的解决scheme。 地图旨在保持唯一的密钥有很好的理由。 虽然如果你真的想这样做, 你总是可以扩展类写一个简单的自定义地图类,它具有碰撞缓解function,并将使您保持多个项目使用相同的键。
注意:您必须实施碰撞减轻function,以便将碰撞的键转换为唯一的“always”。 一些简单的东西,附encryption钥与对象哈希码或什么的?
为了完整,Apache Commons Collections也有一个MultiMap 。 当然,缺点是Apache Commons不使用generics。
有点破解你可以使用重复键HashSet。 警告:这是严重依赖HashSet实现。
class MultiKeyPair { Object key; Object value; public MultiKeyPair(Object key, Object value) { this.key = key; this.value = value; } @Override public int hashCode() { return key.hashCode(); } } class MultiKeyList extends MultiKeyPair { ArrayList<MultiKeyPair> list = new ArrayList<MultiKeyPair>(); public MultiKeyList(Object key) { super(key, null); } @Override public boolean equals(Object obj) { list.add((MultiKeyPair) obj); return false; } } public static void main(String[] args) { HashSet<MultiKeyPair> set = new HashSet<MultiKeyPair>(); set.add(new MultiKeyPair("A","a1")); set.add(new MultiKeyPair("A","a2")); set.add(new MultiKeyPair("B","b1")); set.add(new MultiKeyPair("A","a3")); MultiKeyList o = new MultiKeyList("A"); set.contains(o); for (MultiKeyPair pair : o.list) { System.out.println(pair.value); } }
我用这个:
java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();
class DuplicateMap<K, V> { enum MapType { Hash,LinkedHash } int HashCode = 0; Map<Key<K>,V> map = null; DuplicateMap() { map = new HashMap<Key<K>,V>(); } DuplicateMap( MapType maptype ) { if ( maptype == MapType.Hash ) { map = new HashMap<Key<K>,V>(); } else if ( maptype == MapType.LinkedHash ) { map = new LinkedHashMap<Key<K>,V>(); } else map = new HashMap<Key<K>,V>(); } V put( K key, V value ) { return map.put( new Key<K>( key , HashCode++ ), value ); } void putAll( Map<K, V> map1 ) { Map<Key<K>,V> map2 = new LinkedHashMap<Key<K>,V>(); for ( Entry<K, V> entry : map1.entrySet() ) { map2.put( new Key<K>( entry.getKey() , HashCode++ ), entry.getValue()); } map.putAll(map2); } Set<Entry<K, V>> entrySet() { Set<Entry<K, V>> entry = new LinkedHashSet<Map.Entry<K,V>>(); for ( final Entry<Key<K>, V> entry1 : map.entrySet() ) { entry.add( new Entry<K, V>(){ private K Key = entry1.getKey().Key(); private V Value = entry1.getValue(); @Override public K getKey() { return Key; } @Override public V getValue() { return Value; } @Override public V setValue(V value) { return null; }}); } return entry; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("{"); boolean FirstIteration = true; for ( Entry<K, V> entry : entrySet() ) { builder.append( ( (FirstIteration)? "" : "," ) + ((entry.getKey()==null) ? null :entry.getKey().toString() ) + "=" + ((entry.getValue()==null) ? null :entry.getValue().toString() ) ); FirstIteration = false; } builder.append("}"); return builder.toString(); } class Key<K1> { K1 Key; int HashCode; public Key(K1 key, int hashCode) { super(); Key = key; HashCode = hashCode; } public K1 Key() { return Key; } @Override public String toString() { return Key.toString() ; } @Override public int hashCode() { return HashCode; } }