在地图中我们有键值对。如果我们尝试将相同的键放在地图中2次就会产生错误。现在我也想要类似于行为的值。简而言之,当我放一个新键时,值在映射中,键和值都应该是唯一的,否则它应该通过异常, 我怎么能做到这一点?
答案 0 :(得分:5)
bimap(或“双向地图”)是一个 保留唯一性的地图 它的价值以及它的价值 键。此约束启用了bimaps 支持“逆视图”,即 另一个含有相同的bimap 作为这个bimap的条目,但有 反转键和值。
(一般来说,番石榴是一个很棒的图书馆,顺便说一句。值得使用。)
答案 1 :(得分:3)
您可能希望将HashMap子类化以创建自己的bimap:
改变主意 - 没有必要继承HashMap。 合成是一种更清晰的方法,下面的示例装饰具有BiMap行为的具体地图。
public class BiMap<K, V> implements Map<K, V> {
private Map<K, V> inner;
private Set<V> values;
public BiMap(Map<K, V> map) {
if (map == null || !map.isEmpty())
throw new IllegalArgumentException("This implementation requires an empty map");
inner = map;
values = new HashSet<V>();
}
public boolean containsKey(Object key) { return inner.containsKey(key); }
public boolean containsValue(Object value) { return values.contains(value); }
public Set<java.util.Map.Entry<K, V>> entrySet() { return inner.entrySet(); }
public V get(Object key) { return inner.get(key); }
public boolean isEmpty() { return inner.isEmpty(); }
public Set<K> keySet() { return inner.keySet(); }
public int size() { return inner.size(); }
public Set<V> values() { return Collections.unmodifiableSet(values); }
public boolean equals(Object obj) { return inner.equals(obj); }
public int hashCode() { return inner.hashCode(); }
public String toString() { return inner.toString(); }
public void clear() {
values.clear();
inner.clear();
}
public V put(K key, V value) {
if (values.contains(value)) {
throw new IllegalArgumentException("Value already exists in map");
}
values.add(value);
return inner.put(key, value);
}
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
public V remove(Object key) {
values.remove(key);
return inner.remove(key);
}
}
与子类化现有地图相比,它的代码更多,但值得。现在我们完全独立于任何现有的Map实现。
答案 2 :(得分:2)
创建一个包含Map的新类,以及一组值。在插入时,如果值在集合中,则抛出异常(或返回false,或不执行任何操作),否则将其添加到地图中。
因此,您可以使用Map强制使用唯一键,并使用Set来强制使用唯一值。
如果你想要一个双向地图,那么只需用地图
替换这个集合答案 3 :(得分:1)
免责声明:我肯定会使用Google Collections。它可能是我用过的最优质的库(它有很棒的API,很棒的代码和很棒的文档)。
您可以根据现有的Map实现之一实现自己的Map:
public class UniqueValuesMap<K,V> implements Map<K,V> {
private final Map<K, V> innerMap = new HashMap<K, V> ();
public int size() {
return innerMap.size();
}
...
//all other methods
public V put(K key, V value) {
if (innerMap.values().contains (value) {
throw new IllegalArgumentException ("some msg");
}
return innerMap.put (key, value);
}
public void putAll(Map<? extends K, ? extends V> m) {
// implementation
}
}
答案 4 :(得分:0)
在将值插入地图之前,请使用Map.containsKey
和/或Map.containsValue
进行检查(不确定是否要替换已存在的键的值)。
编辑:有大量插入时的错误答案,仍然适用于小型数据集。
16384随机字符串的插入: 地图12828 ms bimap 31 ms
1024个随机字符串插入:map 32 ms bimap 15 ms
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import com.google.common.collect.HashBiMap;
public class InsertTest
{
private Map<Integer, String> map = new HashMap<Integer, String>();
private Map<Integer, String> bimap = HashBiMap.create();
public void run()
{
String[] values = new String[1024];
Random r = new Random();
for (int i = 0; i < values.length; i++)
{
values[i] = Long.toString(Math.abs(r.nextLong()), 36);
}
test("map", map, values);
test("bimap", bimap, values);
}
private static void test(String name, Map<Integer, String> map, String[] values)
{
int key = 0;
long start = System.currentTimeMillis();
for (String value : values)
{
if (!map.containsValue(value))
{
map.put(key++, value);
}
}
long end = System.currentTimeMillis();
System.out.println(name + " " + (end - start));
}
public static void main(String[] args)
{
new InsertTest().run();
}
}