【问题标题】:MultiKey HashMap ImplementationMultiKey HashMap 实现
【发布时间】:2016-01-21 21:17:19
【问题描述】:

我正在寻找单值的 MultiKey(实际上是 DoubleDouble)的实现。 * 但是 *您可以通过 ONE OF THE KEYS 访问该值! 意思是,访问地图时不必同时拥有两个键。

我知道我可以写一些东西来满足我的要求 - 但问题是那里是否有已经写好的东西,所以我可以开箱即用地使用它。

谢谢:-)

编辑: 在这一点上,我能想到的最好的实现是这样的:

class DoubleKeyHashMap<K1, K2, V> {
    BiMap<K1, K2> keys; // Bidirectional map
    Map<K2, V> values;
..
..
}

【问题讨论】:

  • 我很久以前在这里问过这个问题,没有找到任何东西,我认为它仍然存在。哇,那是六年前的事了:Any implementation of Map<K1, K2, V>, i.e. two keys?
  • 这不就是两张地图K1-&gt;VK2-&gt;V一样吗?
  • 如果地图是通过两个键(k1和k2),而你只通过一个键值(k2)查找,你期望的返回值是多少?与 k2 匹配的所有值的列表?如果是这样,则需要类似于具有多个索引的 SQL 表(为了性能),在这种情况下,它根本不是 Map
  • @Shvalb 映射不允许一个键有多个值,因此您的编辑将不起作用,除非所有对象都有不同的 k1 值和不同的 k2 值,或者使用 SQL 类比,如果两者都有k1 索引和 k2 索引是唯一的。您的问题中没有任何内容表明情况如此。如果它们是独立唯一的,那么双地图解决方案是最好的,我不确定您为什么认为“昂贵”。

标签: java collections


【解决方案1】:

这似乎是实现多键映射的良好开端。

编辑添加了一个 removeElement 方法,并保存并返回一个值列表。

package com.ggl.testing;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class MultiMap<K, V> {

    private static long sequence = 0;

    private Map<K, Long> key1Map;
    private Map<K, Long> key2Map;
    private Map<Long, List<V>> valueMap;

    public MultiMap() {
        this.key1Map = new HashMap<>();
        this.key2Map = new HashMap<>();
        this.valueMap = new HashMap<>();
    }

    public void addElement(K key1, K key2, V value) {
        boolean key1boolean = key1Map.containsKey(key1);
        boolean key2boolean = key2Map.containsKey(key2);
        boolean key3boolean = key1Map.containsKey(key2);
        boolean key4boolean = key2Map.containsKey(key1);

        if (key1boolean && key2boolean) {
            Long key1Value = key1Map.get(key1);
            Long key2Value = key2Map.get(key2);
            updateValue(key1, key2, key1Value, key2Value, value);
        } else if (key3boolean && key4boolean) {
            Long key1Value = key1Map.get(key2);
            Long key2Value = key2Map.get(key1);
            updateValue(key1, key2, key1Value, key2Value, value);
        } else if (key1boolean || key4boolean) {
            String s = displayDuplicateError(key1);
            throw new IllegalStateException(s);
        } else if (key2boolean || key3boolean) {
            String s = displayDuplicateError(key2);
            throw new IllegalStateException(s);
        } else {
            createValue(key1, key2, value);
        }

    }

    private void createValue(K key1, K key2, V value) {
        Long newKeyValue = sequence++;
        key1Map.put(key1, newKeyValue);
        key2Map.put(key2, newKeyValue);

        List<V> values = new ArrayList<>();
        values.add(value);
        valueMap.put(newKeyValue, values);
    }

    private void updateValue(K key1, K key2, Long key1Value, Long key2Value,
            V value) {
        if (key1Value.equals(key2Value)) {
            List<V> values = valueMap.get(key1Value);
            values.add(value);
            valueMap.put(key1Value, values);
        } else {
            String s = displayMismatchError(key1, key2);
            throw new IllegalStateException(s);
        }
    }

    private String displayMismatchError(K key1, K key2) {
        return "Keys " + key1.toString() + " & " + key2.toString()
                + " have a different internal key.";
    }

    private String displayDuplicateError(K key) {
        return "Key " + key.toString() + " is part of another key pair";
    }

    public List<V> getElement(K key) {
        if (key1Map.containsKey(key)) {
            return valueMap.get(key1Map.get(key));
        }

        if (key2Map.containsKey(key)) {
            return valueMap.get(key2Map.get(key));
        }

        return null;
    }

    public boolean removeElement(K key) {
        if (key1Map.containsKey(key)) {
            Long key1Value = key1Map.get(key);
            Set<Entry<K, Long>> entrySet = key2Map.entrySet();
            K key2 = getOtherKey(key1Value, entrySet);

            valueMap.remove(key1Value);
            key1Map.remove(key);
            key2Map.remove(key2);

            return true;
        } else if (key2Map.containsKey(key)) {
            Long key2Value = key2Map.get(key);
            Set<Entry<K, Long>> entrySet = key1Map.entrySet();
            K key1 = getOtherKey(key2Value, entrySet);

            valueMap.remove(key2Value);
            key1Map.remove(key1);
            key2Map.remove(key);

            return true;
        }

        return false;
    }

    private K getOtherKey(Long key1Value, Set<Entry<K, Long>> entrySet) {
        Iterator<Entry<K, Long>> iter = entrySet.iterator();
        K key = null;
        while (iter.hasNext() && key == null) {
            Entry<K, Long> entry = iter.next();
            if (entry.getValue().equals(key1Value)) {
                key = entry.getKey();
            }
        }
        return key;
    }

    public static void main(String[] args) {
        MultiMap<String, String> multiMap = new MultiMap<>();

        try {
            multiMap.addElement("one", "two", "numbers");
            multiMap.addElement("alpha", "beta", "greek alphabet");
            multiMap.addElement("beta", "alpha", "alphabet");
            multiMap.addElement("iron", "oxygen", "elements");
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(Arrays.toString(multiMap.getElement("iron")
                .toArray()));
        System.out.println(Arrays.toString(multiMap.getElement("beta")
                .toArray()));

        System.out.println(multiMap.removeElement("two"));
    }

}

【讨论】:

  • 您如何看待上面出现的“EDIT”。它使用 BiMap 和 HashMap。它是专为 DoubleKeys 设计的解决方案,而不是一般的 MultiKeys。
  • 我会尝试在 Github 上分享。
猜你喜欢
  • 2017-10-10
  • 2014-06-30
  • 1970-01-01
  • 1970-01-01
  • 2017-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多