多键映射获取方法

7
我想使用Apache Collection中的MultiKeyMap,因为我需要一个具有两个键和一个值的HashMap。 要放入元素,我这样做:
private MultiKeyMap multiKey = new MultiKeyMap();
multiKey.put("key1.1", "key2.1", "value1");

获取元素的方法如下:

String s = multiKey.get("key1.1");

但是字符串 s 变成了 null... 如果我传递了两个键,像这样:

String s = multiKey.get("key1.1", "key2.1");

字符串s带有值 value1...

我该如何扩展MultiKeyMap以在我只传递两个键中的一个时获得正确的值?


使用普通的哈希映射表?https://dev59.com/oHRA5IYBdhLWcg3wzhNY - NimChimpsky
10个回答

5
如果您使用两个键来指定一个值,那么获取该值时必须同时使用这两个键。哈希函数并不设计返回与其中任意一个键相关的所有可能的值。您可能需要寻找另一种数据结构来完成这个任务。

5
如果您只需要一个键来获取一个值,那么您可以使用普通的HashMap。
private Map<String, String> map = new HashMap<>();

map.put("key1.1", "value1");
map.put("key2.1", "value1");

获取元素的方法如下:

String s = map.get("key1.1"); // s == "value1"

当需要提供两个键时,必须使用MultiKeyMap。


2
MultiKeyMap是使用元组作为键,而不是将一个值与多个键匹配。使用普通的map,只需用不同的键两次放入您的值即可。
在删除值时需要更加谨慎。当您删除第一个键的值时,是否希望自动删除具有相同值的其他键?如果是这样,您需要循环遍历所有键,并手动删除具有相同值的键,这可能效率低下,或者保留某种反向映射以快速查找特定值的键。

2

我不知道您的问题的确切解决方案,但我建议您按照以下方式实现:

Map<K2, K1> m2;
Map<K1, V>  m1;

请参考:如何实现具有多个键的Map?

(该链接为英文原文,可供参考)


1

看起来你并不需要MultiKeyMap,而是需要普通的map。使用它,你可以将同一个值与任意多个键关联起来。

Map<String, String> map = new HashMap<String, String>();
Object value = .....
map.put("key1", value);
map.put("key2", value);

..................

if(map.get("key1") == map.get("key2")) {
    System.out.println("the same value stored under 2 different keys!");
}

0

你可以使用Guava中的表格数据结构。


0

你不能这样做,因为 MultiKeyMap 不是这样工作的。使用不同的键来存储值,然后逐个键尝试获取它。


0
有点晚了,但你可能想要从地图中获取与第一个元素匹配的每个结果,即使它包含多个结果,也忽略第二个键(通配符效果)。Apache的MultiKeyMap不适用于此。
您可以通过使用MultiKeyMap的MultiKey创建自己的过滤功能来解决此问题。首先,仅过滤出相关的MultiKeys(这些MultiKeys来自yourMultiKeyMap.keySet())。以下方法接受那些multiKeys和您要过滤的第一个键:
private Set<MultiKey<? extends String>> filterMultiKeys(Set<MultiKey<? extends String>> multiKeys, final String... keys) {
    
    final List<String> givenKeys = Arrays.asList(keys);
    
    return multiKeys.stream().filter(multiKey -> {

        final Object[] actualKeys = multiKey.getKeys();
        if (actualKeys.length < givenKeys.size()) {
            
            // Lesser keys, so never a match
            return false;
        }

        final List<Object> trimmedKeys = Arrays.asList(actualKeys).subList(0, givenKeys.size());
        return trimmedKeys.equals(givenKeys);
        
    }).collect(Collectors.toSet());
}

然后,使用生成的MultiKeys来获取结果:
    final Set<String> results = filteredKeys.stream().map(multiKey -> yourMultiKeyMap.get(multiKey)).collect(Collectors.toSet());

为了获得额外的积分,可以扩展或装饰MultiKeyMap并创建MyMultiKeyMap,使用过滤功能具有match(keys...)方法。

0
我建议为多个键创建一个单独的类:
public class Test {

Map<Shape, Book> test1 = new HashMap<>();
Book book = new Book("A");
test1.put(Shape, book);


private class Shape {
  String id1;
  String id2;
public Shape(String id1, String id2) {
  this.id1 = id1;
  this.id2 = id2;
}
 @Override
 public boolean equals(Object o) {//}
@Override
public int hashCode() {//}
}

}

0
这是一个对我有效的简单MultiKeyMap实现。
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

public class MultiMap<K, V> implements Map<K, V>
{
    private class MultiMapEntery implements java.util.Map.Entry<K, V>
    {
        private final K key;
        private V value;

        public MultiMapEntery(K key, V value)
        {
            this.key = key;
            this.value = value;
        }
        @Override
        public K getKey()
        {
            return key;
        }

        @Override
        public V getValue()
        {
            return value;
        }

        @Override
        public V setValue(V value)
        {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }
    };

    private final Map<K, String> keyMap = new HashMap<K, String>();
    private final Map<String, Set<K>> inverseKeyMap = new HashMap<String, Set<K>>();
    private final Map<String, V> valueMap = new HashMap<String, V>();

    @Override
    public void clear()
    {
        keyMap.clear();
        inverseKeyMap.clear();
        valueMap.clear();
    }

    @Override
    public boolean containsKey(Object key)
    {
        return keyMap.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value)
    {
        return valueMap.containsValue(value);
    }

    @Override
    public Set<java.util.Map.Entry<K, V>> entrySet()
    {
        Set<java.util.Map.Entry<K, V>> entries = new HashSet<>();
        for(K key : keyMap.keySet())
        {
            V value = valueMap.get(key);
            entries.add(new MultiMapEntery(key, value));
        }
        return entries;
    }

    @Override
    public V get(Object key)
    {
        return valueMap.get(keyMap.get(key));
    }

    @Override
    public boolean isEmpty()
    {
        return valueMap.isEmpty();
    }

    @Override
    public Set<K> keySet()
    {
        return keyMap.keySet();
    }

    @Override
    public V put(K key, V value)
    {
        String id = keyMap.get(key);
        if(id == null)
        {
            id = UUID.randomUUID().toString();
        }
        keyMap.put(key, id);
        Set<K> keys = inverseKeyMap.get(id);
        if(keys == null)
        {
            keys = new HashSet<>();
        }
        keys.add(key);
        inverseKeyMap.put(id, keys);
        valueMap.put(id, value);
        return value;
    }

    public V put(Set<K> keys, V value)
    {
        String id = null;
        for(K key : keys)
        {
            id = keyMap.get(key);
            if(id != null) // one of the keys already exists
            {
                break;
            }
        }

        if(id == null)
        {
            id = UUID.randomUUID().toString();
        }

        for(K key : keys)
        {
            keyMap.put(key, id);
        }
        inverseKeyMap.put(id, keys);
        valueMap.put(id, value);
        return value;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> map)
    {
        for(java.util.Map.Entry<? extends K, ? extends V> entry : map.entrySet())
        {
            put(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public V remove(Object key)
    {
        String id = keyMap.get(key);
        keyMap.remove(key);
        Set<K> keys = inverseKeyMap.get(id);
        keys.remove(key);
        V value = valueMap.get(id);
        if(keys.size() == 0) // it was the last key, now remove the value
        {
            valueMap.remove(id);
        }
        return value;
    }

    @Override
    public int size()
    {
        return valueMap.size();
    }

    @Override
    public Collection<V> values()
    {
        return valueMap.values();
    }

    public static void main(String[] args)
    {
        MultiMap<String, String> m = new MultiMap<>();
        m.put("a", "v1");
        Set<String> s = new HashSet<>();
        s.add("b");
        s.add("c");
        s.add("d");
        m.put(s, "v2");

        System.out.println("size:"  + m.size());
        System.out.println("keys:"  + m.keySet());
        System.out.println("values:"  + m.values().toString());
        System.out.println("a:" + m.get("a"));
        System.out.println("b:" + m.get("b"));
        System.out.println("c:" + m.get("c"));
        System.out.println("d:" + m.get("d"));

        m.remove("a");

        System.out.println("size:"  + m.size());
        System.out.println("keys:"  + m.keySet());
        System.out.println("values:"  + m.values().toString());
        System.out.println("a:" + m.get("a"));
        System.out.println("b:" + m.get("b"));
        System.out.println("c:" + m.get("c"));
        System.out.println("d:" + m.get("d"));

        s.add("a");
        m.put(s, "v3");

        System.out.println("size:"  + m.size());
        System.out.println("keys:"  + m.keySet());
        System.out.println("values:"  + m.values().toString());

        System.out.println("a:" + m.get("a"));
        System.out.println("b:" + m.get("b"));
        System.out.println("c:" + m.get("c"));
        System.out.println("d:" + m.get("d"));
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接