Domanda

Voglio avere una mappa con chiavi duplicate.

So che ci sono molte implementazioni di mappe (Eclipse me ne mostra circa 50), quindi scommetto che ce ne deve essere una che lo consenta.So che è facile scrivere la tua mappa che faccia questo, ma preferirei usare qualche soluzione esistente.

Forse qualcosa in commons-collections o google-collections?

È stato utile?

Soluzione

È alla ricerca di un multimap, e in effetti entrambi i commons-collezioni e Guava sono disponibili diverse implementazioni per questo. Multimaps consentono di chiavi multiple mantenendo un insieme di valori per chiave, vale a dire si può mettere un singolo oggetto nella mappa, ma recuperare una collezione.

Se è possibile utilizzare Java 5, preferirei di Guava Multimap in quanto è in grado di riconoscere i generici.

Altri suggerimenti

Non abbiamo bisogno di dipendere da Google collezioni libreria esterna. Si può semplicemente implementare la seguente mappa:

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);
}

Assicurati di mettere a punto il codice.

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));

L'uscita è:

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

Nota: abbiamo bisogno di importare file di libreria

.

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

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

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

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

Si potrebbe semplicemente passare una matrice di valori per il valore in un HashMap regolare, simulando così chiavi duplicate, e sarebbe fino a voi decidere quali dati da utilizzare.

Si può anche semplicemente usare un MultiMap , anche se non mi piace l'idea di chiavi duplicate me stesso.

Se si desidera iterare su un elenco di valore di coppie di chiavi (come hai scritto nel commento), poi un elenco o una matrice dovrebbe essere migliore. Prima di combinare le chiavi e valori:

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

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

}

Sostituire Class1 e Class2 con i tipi che si desidera utilizzare per le chiavi e valori.

Ora si può mettere in un array o una lista e scorrere su di loro:

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

MultiValueMap class

Questo problema può essere risolto con una lista di carta ingresso List<Map.Entry<K,V>>. Non abbiamo bisogno di utilizzare né librerie esterne né nuova implementazione di Map. Una voce di mappa può essere creato in questo modo:     Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);

imparare dai miei errori ... per favore non implementare da soli. Guava MultiMap è la strada da percorrere.

Un miglioramento comune required multimaps è non consentire coppie duplicate chiavi-valore.

L'implementazione / modifica questo in una propria implementazione può essere fastidioso.

Nella Guava sua semplice come:

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

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

Ho avuto un po 'diversa variante di questo problema: E' stato richiesto di associare due valori diversi con stessa chiave. Basta postare qui nel caso in cui aiuta gli altri, ho introdotto una HashMap come valore:

/* @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 );
        }
}

Nel codice sopra il frameID chiave viene letta dalla prima stringa di un file di input in ogni riga, il valore per frameTypeHash è costruita suddividendo la linea rimanente e stato memorizzato come oggetto String inizialmente, per un periodo di tempo file cominciato avere più linee (con valori diversi) associati con la stessa chiave frameID, così frameTypeHash è sovrascritto con ultima riga come valore. Ho sostituito l'oggetto String con un altro oggetto HashMap come il campo del valore, questo ha aiutato a mantenere la sola chiave per la mappatura valore diverso.

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;
        }
    }

Potresti anche spiegare il contesto per il quale stai cercando di implementare una mappa con chiavi duplicate?Sono sicuro che potrebbe esserci una soluzione migliore.Le mappe hanno lo scopo di mantenere chiavi univoche per una buona ragione.Anche se davvero volessi farlo;puoi sempre estendere la classe scrivendo una semplice classe di mappa personalizzata che abbia una funzione di mitigazione delle collisioni e ti consenta di mantenere più voci con le stesse chiavi.

Nota:È necessario implementare la funzione di mitigazione delle collisioni in modo tale che le chiavi in ​​collisione vengano convertite in un set univoco "sempre".Qualcosa di semplice come aggiungere la chiave con l'hashcode dell'oggetto o qualcosa del genere?

solo per essere completa, Apache Commons Collections ha anche un MultiMap . Il rovescio della medaglia, naturalmente, è che Apache Commons non fa uso di farmaci generici.

Con un po 'hack possibile utilizzare HashSet con chiavi duplicate. ATTENZIONE: questo è fortemente HashSet attuazione dipendente.

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);
    }
}

Se ci sono chiavi duplicate poi una chiave può corrispondere a più di un valore. La soluzione più ovvia è quella di mappare la chiave per un elenco di questi valori.

Ad esempio 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

Ho usato questa:

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

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

questa soluzione dettagliato ha molteplici inconvenienti ed è soggetto a errori. esso       implica che abbiamo bisogno di istanziare una collezione per ogni valore, verificare la presenza di       la sua presenza prima di aggiungere o rimuovere un valore, eliminarlo manualmente quando nessun       I valori sono lasciati, eccetera.

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

java-map--chiavi duplicate

che dire di un tale impl MultiMap?

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() .....

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top