Frage

Ich möchte eine Karte mit Nachschlüssel haben.

Ich weiß, es gibt viele Karte Implementierungen (Eklipse zeigt mir etwa 50), so dass ich wette, es sein muss, die dies ermöglicht. Ich weiß, es ist einfach, Ihre eigene Karte zu schreiben, der dies tut, aber ich würde lieber einige bestehende Lösung verwenden.

Vielleicht etwas in commons-Sammlungen oder google-Sammlungen?

War es hilfreich?

Lösung

Sie suchen nach einem multimap, und zwar beide commons-Sammlungen und Guava haben mehrere Implementierungen dafür. Multimaps für mehrere Schlüssel erlauben durch eine Sammlung von Werten pro Schlüssel beibehalten, das heißt Sie ein einzelnes Objekt in die Karte setzen kann, aber Sie rufen Sie eine Sammlung.

Wenn Sie 5 Java verwenden können, würde ich Guava der Multimap , wie es ist Generika-aware.

Andere Tipps

Wir brauchen nicht auf die Google Kollektionen externe Bibliothek abhängen. Sie können einfach implementieren, um die folgende Karte:

Map<String, ArrayList<String>> hashMap = new HashMap<String, ArrayList>();

public static void main(String... arg) {
   // Add data with duplicate keys
   addValues("A", "a1");
   addValues("A", "a2");
   addValues("B", "b");
   // View data.
   Iterator it = hashMap.keySet().iterator();
   ArrayList tempList = null;

   while (it.hasNext()) {
      String key = it.next().toString();             
      tempList = hashMap.get(key);
      if (tempList != null) {
         for (String value: tempList) {
            System.out.println("Key : "+key+ " , Value : "+value);
         }
      }
   }
}

private void addValues(String key, String value) {
   ArrayList tempList = null;
   if (hashMap.containsKey(key)) {
      tempList = hashMap.get(key);
      if(tempList == null)
         tempList = new ArrayList();
      tempList.add(value);  
   } else {
      tempList = new ArrayList();
      tempList.add(value);               
   }
   hashMap.put(key,tempList);
}

Bitte stellen Sie sicher, den Code für die Feinabstimmung.

Multimap<Integer, String> multimap = ArrayListMultimap.create();

multimap.put(1, "A");
multimap.put(1, "B");
multimap.put(1, "C");
multimap.put(1, "A");

multimap.put(2, "A");
multimap.put(2, "B");
multimap.put(2, "C");

multimap.put(3, "A");

System.out.println(multimap.get(1));
System.out.println(multimap.get(2));       
System.out.println(multimap.get(3));

Die Ausgabe ist:

[A,B,C,A]
[A,B,C]
[A]

Hinweis: müssen wir Bibliotheksdateien importieren

.

http://www.java2s.com/Code/Jar/g/ Downloadgooglecollectionsjar.htm

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

oder https://commons.apache.org/proper/commons-collections /download_collections.cgi

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;

Sie könnten einfach ein Array von Werten für den Wert in einem regelmäßigen HashMap passieren, damit doppelte Schlüssel zu simulieren, und es wäre an Sie zu entscheiden, welche Daten zu verwenden.

Sie können auch einfach verwenden ein MultiMap , obwohl ich mag die Idee von Nachschlüssel mich nicht.

Wenn Sie iterieren wollen über eine Liste von Schlüssel-Wert-Paaren (wie Sie in dem Kommentar geschrieben haben), dann eine Liste oder ein Array sollte besser sein. Zuerst kombinieren Sie Ihre Schlüssel und Werte:

public class Pair
{
   public Class1 key;
   public Class2 value;

   public Pair(Class1 key, Class2 value)
   {
      this.key = key;
      this.value = value;
   }

}

Ersetzen Class1 und Class2 mit den Typen, die Sie für Schlüssel und Werte verwendet werden sollen.

Jetzt können Sie sie in ein Array oder in einem Verzeichnis und durchlaufen sie:

Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
   ...
}
commons.apache.org

MultiValueMap class

Dieses Problem kann mit einer Liste der MapEintrag List<Map.Entry<K,V>> gelöst werden. Wir brauchen keine weder externe Bibliotheken zu verwenden, noch neue Implementierung von Karte. Ein Map-Eintrag kann wie folgt erstellt werden:     Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);

aus meinen Fehlern lernen ... Bitte nicht implementieren diese auf eigene Faust. Guava multimap ist der Weg zu gehen.

Eine gemeinsame Erweiterung in multimaps erforderlich ist, um doppelte Schlüssel-Wert-Paare nicht zulassen.

Die Implementierung / ändert dies in einer Implementierung kann lästig sein.

In Guava seiner so einfach wie:

HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();

ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();

hatte ich eine etwas andere Variante dieses Problems: Es benötigt wurde zwei verschiedene Werte mit dem gleichen Schlüssel zu verknüpfen. Gerade hier bei Entsendung es anderen hilft, ich habe einen HashMap als Wert eingeführt:

/* @param frameTypeHash: Key -> Integer (frameID), Value -> HashMap (innerMap)
   @param innerMap: Key -> String (extIP), Value -> String
   If the key exists, retrieve the stored HashMap innerMap 
   and put the constructed key, value pair
*/
  if (frameTypeHash.containsKey(frameID)){
            //Key exists, add the key/value to innerHashMap
            HashMap innerMap = (HashMap)frameTypeHash.get(frameID);
            innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);

        } else {
            HashMap<String, String> innerMap = new HashMap<String, String>();
            innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);
            // This means the key doesn't exists, adding it for the first time
            frameTypeHash.put(frameID, innerMap );
        }
}

In dem obigen Code der Schlüssel FrameID ersten String der aus einer Eingabedatei in jeder Zeile gelesen wird, wird der Wert für frameTypeHash konstruiert, indem die verbleibende Linie Aufspalten und wurde als String-Objekt ursprünglich gespeichert ist, über einen bestimmten Zeitraum die Datei gestartet, die mehrere Leitungen (mit verschiedenen Werten) mit gleichen FrameID Schlüssel zugeordnet, so frameTypeHash mit der letzten Zeile wie der Wert überschrieben wurde. Ich ersetzen das String-Objekt mit einem anderen HashMap-Objekt als Wertfeld, das half in einzelne Schlüssel zu unterschiedlichem Werte-Mapping beibehalten wird.

class  DuplicateMap<K, V> 
{
    enum MapType
    {
        Hash,LinkedHash
    }

    int HashCode = 0;
    Map<Key<K>,V> map = null;

    DuplicateMap()
    {
        map = new HashMap<Key<K>,V>();
    }

    DuplicateMap( MapType maptype )
    {
        if ( maptype == MapType.Hash ) {
            map = new HashMap<Key<K>,V>();
        }
        else if ( maptype == MapType.LinkedHash ) {
            map = new LinkedHashMap<Key<K>,V>();
        }
        else
            map = new HashMap<Key<K>,V>();
    }

    V put( K key, V value  )
    {

        return map.put( new Key<K>( key , HashCode++ ), value );
    }

    void putAll( Map<K, V> map1 )
    {
        Map<Key<K>,V> map2 = new LinkedHashMap<Key<K>,V>();

        for ( Entry<K, V> entry : map1.entrySet() ) {
            map2.put( new Key<K>( entry.getKey() , HashCode++ ), entry.getValue());
        }
        map.putAll(map2);
    }

    Set<Entry<K, V>> entrySet()
    {
        Set<Entry<K, V>> entry = new LinkedHashSet<Map.Entry<K,V>>();
        for ( final Entry<Key<K>, V> entry1 : map.entrySet() ) {
            entry.add( new Entry<K, V>(){
                private K Key = entry1.getKey().Key();
                private V Value = entry1.getValue();

                @Override
                public K getKey() {
                    return Key;
                }

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

                @Override
                public V setValue(V value) {
                    return null;
                }});
        }

        return entry;
    }

    @Override
    public String toString() {
        StringBuilder builder = new  StringBuilder();
        builder.append("{");
        boolean FirstIteration = true;
        for ( Entry<K, V> entry : entrySet() ) {
            builder.append( ( (FirstIteration)? "" : "," ) + ((entry.getKey()==null) ? null :entry.getKey().toString() ) + "=" + ((entry.getValue()==null) ? null :entry.getValue().toString() )  );
            FirstIteration = false;
        }
        builder.append("}");
        return builder.toString();
    }

    class Key<K1>
    {
        K1 Key;
        int HashCode;

        public Key(K1 key, int hashCode) {
            super();
            Key = key;
            HashCode = hashCode;
        }

        public K1 Key() {
            return Key;
        }

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

        @Override
        public int hashCode() {

            return HashCode;
        }
    }

Könnten Sie auch den Kontext erklären, für die Sie versuchen, eine Karte mit Nachschlüssel zu implementieren? Ich bin sicher, es könnte eine bessere Lösung. Karten sollen eindeutige Schlüssel aus gutem Grund halten. Obwohl, wenn Sie wirklich wollte, es zu tun; Sie können die Klasse schreiben Sie eine einfache benutzerdefinierte Karte Klasse immer erweitern, die eine Kollisionsschutzfunktion hat und Sie mehrere Einträge mit dem gleichen Schlüssel zu halten ermöglichen würde.

Hinweis: Sie müssen Kollisionsminderungsfunktion implementieren, so dass, kollidieren Schlüssel zum einzigartigen Satz umgewandelt „immer“. Etwas Einfaches wie, Anfügen Schlüssel mit dem Objekt hashcode oder so etwas?

nur auf Vollständigkeit, Apache Commons Collections hat auch eine MultiMap . Der Nachteil ist natürlich, dass Apache Commons nicht Generics nicht verwendet.

Mit etwas hacken Sie HashSet mit doppelten Schlüssel verwenden können. ACHTUNG: Dies ist stark abhängig von der Implementierung HashSet.

class MultiKeyPair {
    Object key;
    Object value;

    public MultiKeyPair(Object key, Object value) {
        this.key = key;
        this.value = value;
    }

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

class MultiKeyList extends MultiKeyPair {
    ArrayList<MultiKeyPair> list = new ArrayList<MultiKeyPair>();

    public MultiKeyList(Object key) {
        super(key, null);
    }

    @Override
    public boolean equals(Object obj) {
        list.add((MultiKeyPair) obj);
        return false;
    }
}

public static void main(String[] args) {
    HashSet<MultiKeyPair> set = new HashSet<MultiKeyPair>();
    set.add(new MultiKeyPair("A","a1"));
    set.add(new MultiKeyPair("A","a2"));
    set.add(new MultiKeyPair("B","b1"));
    set.add(new MultiKeyPair("A","a3"));

    MultiKeyList o = new MultiKeyList("A");
    set.contains(o);

    for (MultiKeyPair pair : o.list) {
        System.out.println(pair.value);
    }
}

Wenn es doppelte Schlüssel dann ein Schlüssel zu mehr als einem Wert entsprechen. Die offensichtliche Lösung ist der Schlüssel zu einer Liste dieser Werte abzubilden.

Zum Beispiel in Python:

map = dict()
map["driver"] = list()
map["driver"].append("john")
map["driver"].append("mike")
print map["driver"]          # It shows john and mike
print map["driver"][0]       # It shows john
print map["driver"][1]       # It shows mike

Ich habe diese:

java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();

 1, Map<String, List<String>> map = new HashMap<>();
  

Diese ausführliche Lösung hat mehrere Nachteile und ist fehleranfällig. Es       bedeutet, dass wir eine Sammlung für jeden Wert instanziiert benötigen, prüfen       seine Präsenz vor dem Hinzufügen oder einen Wert zu entfernen, löschen Sie es manuell, wenn keine       Werte sind links, und so weiter.

2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface 

java-map-Duplikat-Tasten

, was über eine solche MultiMap impl?

public class MultiMap<K, V> extends HashMap<K, Set<V>> {
  private static final long serialVersionUID = 1L;
  private Map<K, Set<V>> innerMap = new HashMap<>();

  public Set<V> put(K key, V value) {
    Set<V> valuesOld = this.innerMap.get(key);
    HashSet<V> valuesNewTotal = new HashSet<>();
    if (valuesOld != null) {
      valuesNewTotal.addAll(valuesOld);
    }
    valuesNewTotal.add(value);
    this.innerMap.put(key, valuesNewTotal);
    return valuesOld;
  }

  public void putAll(K key, Set<V> values) {
    for (V value : values) {
      put(key, value);
    }
  }

  @Override
  public Set<V> put(K key, Set<V> value) {
    Set<V> valuesOld = this.innerMap.get(key);
    putAll(key, value);
    return valuesOld;
  }

  @Override
  public void putAll(Map<? extends K, ? extends Set<V>> mapOfValues) {
    for (Map.Entry<? extends K, ? extends Set<V>> valueEntry : mapOfValues.entrySet()) {
      K key = valueEntry.getKey();
      Set<V> value = valueEntry.getValue();
      putAll(key, value);
    }
  }

  @Override
  public Set<V> putIfAbsent(K key, Set<V> value) {
    Set<V> valueOld = this.innerMap.get(key);
    if (valueOld == null) {
      putAll(key, value);
    }
    return valueOld;
  }

  @Override
  public Set<V> get(Object key) {
    return this.innerMap.get(key);
  }

  @Override
  etc. etc. override all public methods size(), clear() .....

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top