0

私はプロジェクトに取り組んでおり、キーと値のペア(1対1のマッピング)を順序付けられた方法で格納する必要があります。そうすれば、値を使用してキーを取得し、キーを使用して値を取得できるはずです。マップ、セット、ハッシュテーブルを見てきましたが、順序付けられていません。

また、些細なことですが、DSでキーと値を一度に取得できれば素晴らしいと思います。つまり、インターフェイスはそのような機能をサポートしています。

編集:キーと値はすべて一意です。挿入された順序を維持するだけで十分です。

4

4 に答える 4

2

「順序付き」としてカウントされるものを定義していないことに注意してください。ALinkedHashMapを使用すると、キー(したがって値)を挿入順に繰り返すことができます。逆に、aをTreeMap使用すると、コンパレータを使用して並べ替え順序を指定でき、マップに追加されたすべてのアイテムが並べ替えられた順序で保存されるようになります。100回のうち99回は、これらのクラスの1つで十分です。あるいは、GoogleのGuavaプロジェクトには、ニーズに合った非常に優れたBiMap実装がいくつかあります。

これらのクラスが提供できる以上のものが必要だと思われる場合は、問題を過剰に設計している可能性があります。


完全に正当化できない理由UniqueOrderedBiMapで、Javaコレクションフレームワークと互換性があり、実装されたすべての関数が効率的に実行される適切なものを実装しました。適切と思われる基になるマップ(本当に必要な場合は順序付けされていないマップを含む)を使用でき、キーと値は常に一意です。これは、の周りの非常に薄いラッパーであることに注意してLinkedHashMapください。必要なのはそれだけであり、LinkedHashMap値が一意のままであることを確認するための追加のチェックがあります。

不思議なことに、この回答の改訂履歴で、メソッドとメソッドがUniqueOrderedMapないが、インターフェイスをより適切に実装し、既知の値を格納するためにHashMapではなくHashSetのみが必要であるかどうかを確認してください。getKey()removeKey()Map

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class UniqueOrderedBiMap<K, V>implements Map<K, V> {
    private Map<K, V> orderedMap;
    private HashMap<V, K> valueMap;

    public UniqueOrderedBiMap() {
        this(new LinkedHashMap<K,V>());
    }

    public UniqueOrderedBiMap(Map<K, V> underlyingMap) {
        orderedMap = underlyingMap;
        valueMap = new HashMap<V, K>(orderedMap.size());

        for(Map.Entry<K, V> e : orderedMap.entrySet()) {
            if(!valueMap.containsKey(e.getValue())) { // Duplicate value
                // could instead fail softly by removing the associated item from the map, but this seems cleaner/clearer.
                // generally this constructor should be passed an empty map anyways
                throw new IllegalArgumentException("Duplicate value "+e.getValue()+" found in underlying map.");
            }
            valueMap.put(e.getValue(), e.getKey());
        }
    }

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

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

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

    @Override
    public boolean containsValue(Object value) {
        // more efficient than iterating over the map
        return valueMap.containsKey(value);
    }

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

    public K getKey(V value) {
        return valueMap.get(value);
    }

    // Likely want to implement a forcePut(K, V) method like Guava's BiMaps do
    @Override
    public V put(K key, V value) {
        if(valueMap.containsKey(value)) {
            throw new IllegalArgumentException("Cannot insert non-unique value "+value);
        }
        V ret = orderedMap.put(key, value);
        valueMap.remove(ret);
        valueMap.put(value, key);
        return ret;
    }

    @Override
    public V remove(Object key) {
        V ret = orderedMap.remove(key);
        valueMap.remove(ret);
        return ret;
    }

    public K removeKey(V value) {
        K ret = valueMap.remove(value);
        orderedMap.remove(ret);
        return ret;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        // Existing Map implementation's putAll have some optimizations we
        // could take advantage of, but this isn't unreasonable for a first pass
        for(Entry<? extends K, ? extends V> e : m.entrySet()) {
            put(e.getKey(), e.getValue());
        }
    }

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

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

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

    @Override
    public Set<java.util.Map.Entry<K, V>> entrySet() {
        return orderedMap.entrySet();
    }

    @Override
    public boolean equals(Object o) {
        if(o instanceof UniqueOrderedBiMap) {
            UniqueOrderedBiMap<?,?> map = (UniqueOrderedBiMap<?,?>)o;
            return orderedMap.equals(map.orderedMap); 
        }
        return false;
    }

    @Override
    public int hashCode() {
        return orderedMap.hashCode();
    }

    @Override public String toString() {
        return orderedMap.toString();
    }

    public static void main(String[] args) {
        String[] names = { "Marcus", "Jim", "Tom", "Sam" };
        String[] grades = { "A", "B", "D", "F" };

        UniqueOrderedBiMap<String,String> insertionMap = new UniqueOrderedBiMap<>();
        UniqueOrderedBiMap<String,String> sortedMap = new UniqueOrderedBiMap<>(new TreeMap<String,String>());

        for(int i = 0; i < names.length; i++) {
            insertionMap.put(names[i], grades[i]);
            sortedMap.put(names[i], grades[i]);
        }

        // Poor man's assert
        System.out.println(insertionMap.toString().equals("{Marcus=A, Jim=B, Tom=D, Sam=F}"));
        System.out.println(sortedMap.toString().equals("{Jim=B, Marcus=A, Sam=F, Tom=D}"));

        insertionMap.put("Tom", "C");
        sortedMap.put("Tom", "C");
        System.out.println(insertionMap.toString().equals("{Marcus=A, Jim=B, Tom=C, Sam=F}"));
        System.out.println(sortedMap.toString().equals("{Jim=B, Marcus=A, Sam=F, Tom=C}"));

        try {
            insertionMap.put("Sam", "C");
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
        try {
            sortedMap.put("Sam", "C");
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }

        insertionMap.remove("Tom");
        sortedMap.remove("Tom");
        insertionMap.put("Sam", "C");
        sortedMap.put("Sam", "C");
        System.out.println(insertionMap.toString().equals("{Marcus=A, Jim=B, Sam=C}"));
        System.out.println(sortedMap.toString().equals("{Jim=B, Marcus=A, Sam=C}"));

        insertionMap.removeKey("A");
        sortedMap.removeKey("A");
        System.out.println(insertionMap.toString().equals("{Jim=B, Sam=C}"));
        System.out.println(sortedMap.toString().equals("{Jim=B, Sam=C}"));
    }
}
于 2013-02-19T19:39:57.760 に答える
1

サードパーティのライブラリを使用できる場合は、の使用を検討してImmutableBiMapください。そのグアバコレクションクラスを提供します

  1. ユーザー指定の反復順序
  2. キーから値への法線マッピングと値からキーへの逆マッピング

1つの考慮事項は、一度作成されたマップは不変であり、変更できないことです。

于 2013-02-19T19:42:47.523 に答える
0

LinkedHashMapはあなたに適しているはずです。リンクを読む

于 2013-02-19T19:33:03.803 に答える
0

2つ必要になりますLinkedHashMap。内部で2つを使用するカスタムクラスを作成できますLinkedHashMap。1つはキーを値にマッピングするためのもので、もう1つは値をキーにマッピングするためのものです。

于 2013-02-19T19:33:15.960 に答える