【问题标题】:A Java multimap which allows fast lookup of key by value一个 Java 多映射,它允许按值快速查找键
【发布时间】:2014-07-02 00:12:36
【问题描述】:

我有一个多重地图(就像 Guava 提供的那样):

Multimap<K, V>

逻辑上可以看成:

Map<K, Set<V>>

我的多重地图中的数据具有唯一键和唯一值。即,永远不能为多个键分配相同的值。

除了维护两个 Map 结构之外,有没有人知道现有的类/api 可以让我通过键或值快速查找。

例如

Collection<V> get(K)

...and...

K getKeyByValue(V)

顺便说一句,地图必须是可变的,即我的数据一直在变化。 (对于不可变的地图,Guava 提供了一个 ImmutableMultimap.inverse() 如果我的地图可以是不可变的,它将解决这个问题。)

任何帮助将不胜感激。

【问题讨论】:

  • 请检查此链接是否解决了目的? stackoverflow.com/questions/711618/…
  • 你看过 Guava 的 BiMap 吗?我认为这就是你想要的......虽然,它有两张地图支持(你似乎想要避免的事情)。
  • Guava 没有公开 BiMultimap 类型,因为对这种结构的需求并不是很高,而且它的许多用户可以满足于不可变的版本。
  • 这可能取决于您的地图通常使用的方式。如果 V-to-K 查找速度很关键,并且每个 K 的 V 数量足够低,那么显而易见的解决方案是每个 V 都有对其 K 的引用,每次将 (K,V) 添加到映射或从中删除(显然,这应该以 OOP 方式干净地完成)。这使得 V-to-K 查找 O(1),但 (K,V) 的添加和删除时间要长 O(|V|)。根据用例,它可能是好是坏。
  • 如果我是你,我会创建自己的 Multimap 类,其中包含用于反向查找的内部映射。如果可能,我会避免的困难部分是允许通过返回的视图(keys()、keyset()、asMap() 等)进行间接修改。

标签: java guava multimap


【解决方案1】:

试试这个

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;

public class MyMap<K, V> implements Multimap<K, V> {

    private Multimap<K, V> key2Value = ArrayListMultimap.create();
    private Map<V, K> value2key = Maps.newHashMap();

    public K getKeyByValue(V value) {
        return value2key.get(value);
    }

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

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

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

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

    @Override
    public boolean containsEntry(Object key, Object value) {
        return key2Value.containsEntry(key, value);
    }

    @Override
    public boolean put(K key, V value) {
        value2key.put(value, key);
        return key2Value.put(key, value);
    }

    @Override
    public boolean remove(Object key, Object value) {
        value2key.remove(value);
        return key2Value.remove(key, value);
    }

    @Override
    public boolean putAll(K key, Iterable<? extends V> values) {
        for (V value : values) {
            value2key.put(value, key);
        }
        return key2Value.putAll(key, values);
    }

    @Override
    public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
        for (Entry<? extends K, ? extends V> e : multimap.entries()) {
            value2key.put(e.getValue(), e.getKey());
        }
        return key2Value.putAll(multimap);
    }

    @Override
    public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
        Collection<V> replaced = key2Value.replaceValues(key, values);
        for (V value : replaced) {
            value2key.remove(value);
        }
        for (V value : values) {
            value2key.put(value, key);
        }
        return replaced;
    }

    @Override
    public Collection<V> removeAll(Object key) {
        Collection<V> removed = key2Value.removeAll(key);
        for (V value : removed) {
            value2key.remove(value);
        }
        return removed;
    }

    @Override
    public void clear() {
        value2key.clear();
        key2Value.clear();
    }

    @Override
    public Collection<V> get(K key) {
        return key2Value.get(key);
    }

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

    @Override
    public Multiset<K> keys() {
        return key2Value.keys();
    }

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

    @Override
    public Collection<Entry<K, V>> entries() {
        return key2Value.entries();
    }

    @Override
    public Map<K, Collection<V>> asMap() {
        return key2Value.asMap();
    }

    public static void main(String[] args) {

        MyMap<String, String> map = new MyMap<>();

        map.put("key1", "value1");
        map.put("key1", "value2");
        map.put("key1", "value3");
        map.put("key1", "value4");
        map.put("key2", "value5");

        System.out.println(map.getKeyByValue("value1"));
        System.out.println(map.getKeyByValue("value5"));

    }

}

输出:

key1
key2

【讨论】:

    【解决方案2】:

    我想你可能需要这个类:org.apache.commons.collections.map.MultiValueMap

    它是 ASF commons-collections.jar,文档:http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/map/MultiValueMap.html

    【讨论】:

    • 您的回答并没有解决我最初陈述的问题。因为我追求的是允许按值快速查找键的多映射。 apache MultiValueMap 不提供按值查找键。
    • 很抱歉没有帮到你,但是有一个问题:一个值可能被多个键引用,这将非常复杂,更像是多对多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 2014-07-22
    • 2017-02-05
    • 1970-01-01
    • 2011-02-11
    • 2021-07-01
    相关资源
    最近更新 更多