Question

Je veux avoir une carte avec des clés en double.

Je sais, donc je parie qu'il doit y avoir une, il y a de nombreuses implémentations de carte (Eclipse me montre environ 50) qui permet. Je sais qu'il est facile d'écrire votre propre carte qui fait cela, mais je préfère utiliser une solution existante.

Peut-être quelque chose dans commons-collections ou google-collections?

Était-ce utile?

La solution

Vous recherchez un multimap, et même les deux communes-collections et goyave avez plusieurs implémentations pour cela. Multimaps permettent de multiples clés en maintenant une collection de valeurs par clé, à savoir que vous pouvez mettre un objet dans la carte, mais vous récupérez une collection.

Si vous pouvez utiliser Java 5, je préférerais de goyave Multimap car il est générique SENSIBLE.

Autres conseils

Nous ne devons pas dépendre des collections Google bibliothèque externe. Vous pouvez simplement mettre en œuvre la carte suivante:

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

S'il vous plaît assurez-vous d'affiner le code.

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

sortie est la suivante:

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

Remarque: nous avons besoin de fichiers de bibliothèque importer

.

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

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

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

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

Vous pouvez simplement passer un tableau de valeurs pour la valeur dans une HashMap régulière, simulant ainsi les clés en double, et il serait à vous de décider quelles sont les données à utiliser.

Vous pouvez aussi utiliser un MultiMap , bien que je n'aime pas l'idée de clés en double moi-même.

Si vous voulez itérer sur une liste de paires de valeurs-clés (comme vous avez écrit dans le commentaire), puis une liste ou un tableau devrait être mieux. Tout d'abord combiner vos clés et valeurs:

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

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

}

Remplacer et Class1 Classe2 avec les types que vous souhaitez utiliser pour les clés et les valeurs.

Maintenant, vous pouvez les mettre dans un tableau ou une liste et itérer sur eux:

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

MultiValueMap class

Ce problème peut être résolu avec une liste d'entrée de List<Map.Entry<K,V>> carte. Nous ne devons pas utiliser ni bibliothèques externes ni nouvelle implémentation de Map. Une entrée de la carte peut être créé comme ceci:     Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);

En savoir de mes erreurs ... s'il vous plaît ne pas mettre en œuvre sur votre propre. Goyave multimap est le chemin à parcourir.

Une amélioration commune requise dans multimaps est d'interdire les paires dupliquées touches de valeur.

La mise en œuvre / changer cela dans une implémentation peut être gênant.

Dans Goyave est aussi simple que:

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

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

J'ai eu une variante légèrement différente de cette question: Il est nécessaire d'associer deux valeurs différentes avec la même clé. affichage juste ici dans le cas où il aide les autres, je vous ai présenté un HashMap comme la valeur:

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

Dans le code au-dessus du frameID clé est lu à partir de la première chaîne de caractères d'un fichier d'entrée dans chaque ligne, la valeur de frameTypeHash est réalisé en divisant la ligne restante et a été stocké comme objet Chaîne initialement, sur une période de temps, le fichier a commencé à avoir plusieurs lignes (avec des valeurs différentes) associés avec la même clé de frameID, de sorte frameTypeHash a été remplacée par la dernière ligne en tant que valeur. Je l'ai remplacé l'objet String avec un autre objet HashMap que le champ de valeur, ce qui a contribué à maintenir la clé unique à la cartographie de valeur différente.

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

Pouvez-vous expliquer également le contexte pour lequel vous essayez de mettre en œuvre une carte avec les clés en double? Je suis sûr qu'il pourrait y avoir une meilleure solution. Les cartes sont destinées à maintenir des clés uniques pour une bonne raison. Bien que si vous vouliez vraiment le faire; vous pouvez toujours étendre la classe écrire une simple classe carte personnalisée qui a une fonction d'atténuation des collisions et qui vous permettra de garder les entrées multiples avec les mêmes clés.

Note: Vous devez implémenter la fonction d'atténuation des collisions telles que les clés entrant en collision sont converties en ensemble unique « toujours ». Quelque chose de simple comme, clé avec hashcode annexant objet ou quelque chose?

juste pour être complet, Apache Commons Collections a également MultiMap . L'inconvénient est bien sûr que Apache Commons n'utilise pas Generics.

Avec un peu pirater, vous pouvez utiliser HashSet avec des clés en double. AVERTISSEMENT: cela dépend fortement HashSet mise en œuvre.

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

Si des clés en double alors une clé peut correspondre à plus d'une valeur. La solution évidente consiste à cartographier la clé d'une liste de ces valeurs.

Par exemple en 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

je ceci:

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

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

cette solution verbeux a de multiples inconvénients et est sujette à des erreurs. Il       implique que nous devons instancier une collection pour chaque valeur, vérifiez       sa présence avant d'ajouter ou de supprimer une valeur, supprimer manuellement en l'absence de       les valeurs sont à gauche, etcetera.

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

clés-en double-java-carte

Qu'en est-il un tel 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() .....

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top