web-dev-qa-db-fra.com

Implémentation de la carte avec des clés dupliquées

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

Je sais qu'il existe de nombreuses implémentations de cartes (Eclipse m'en montre environ 50), alors je parie qu'il doit y en avoir une qui permet cela. Je sais qu'il est facile d'écrire votre propre carte, mais je préférerais utiliser une solution existante.

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

98
IAdapter

Vous recherchez une carte multiple, et effectivement, les deux collections communes et Guava ont plusieurs implémentations pour cela. Les cartes multimédias permettent l’utilisation de plusieurs clés en conservant une collection de valeurs par clé, c’est-à-dire que vous pouvez insérer un seul objet dans la carte, mais vous récupérez une collection.

Si vous pouvez utiliser Java 5, je préférerais que Multimap de Guava soit générique.

80
nd.

Nous n'avons pas besoin de dépendre de la bibliothèque externe Google Collections. Vous pouvez simplement implémenter 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.

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

La sortie est: 

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

Remarque: nous devons importer des fichiers de bibliothèque.

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;
23
Issac Balaji

Vous pouvez simplement transmettre un tableau de valeurs pour la valeur dans un HashMap standard, simulant ainsi des clés en double, et il vous appartient de décider des données à utiliser.

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

17
AlbertoPL

Si vous voulez parcourir une liste de paires clé-valeur (comme vous l'avez écrit dans le commentaire), une liste ou un tableau devrait être préférable. Commencez par combiner vos clés et vos valeurs:

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

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

}

Remplacez Class1 et Class2 par 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 les parcourir:

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

MultiValueMap class
5
Ravi Parekh

Apprenez de mes erreurs ... s'il vous plait, n'appliquez pas ceci vous-même .

Une amélioration commune requise dans les cartes multimédias consiste à interdire les paires clé-valeur en double.

Implémenter/changer cela dans votre implémentation peut être ennuyeux.

En goyave, c'est aussi simple que:

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

ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();
3
frostbite
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;
        }
    }
1
Gabrial David

J'avais une variante légèrement différente de ce problème: il était nécessaire d'associer deux valeurs différentes avec la même clé. En le postant ici au cas où cela aiderait les autres, j'ai introduit un HashMap comme 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 ci-dessus, la clé frameID est lue à partir de la première chaîne d'un fichier d'entrée dans chaque ligne, la valeur de frameTypeHash est construite en scindant la ligne restante et a été stockée en tant qu'objet String à l'origine, sur une période donnée, le fichier a commencé à comporter plusieurs lignes ( avec des valeurs différentes) associées à la même clé frameID, donc frameTypeHash a été écrasé avec la dernière ligne comme valeur. J'ai remplacé l'objet String par un autre objet HashMap en tant que champ de valeur, ce qui a permis de maintenir le mappage d'une clé vers une autre valeur.

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

cette solution verbeuse présente plusieurs inconvénients et est sujette aux 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, supprimez-la manuellement lorsque non. les valeurs sont laissées, etc.

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

Java-map-duplicate-keys

0
Vicky

pour être complet, Apache Commons Collections possède également un MultiMap . L’inconvénient est qu’Apache Commons n’utilise pas de génériques.

0
newacct

qu'en est-il d'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() .....

}
0
george

Pourriez-vous également expliquer le contexte dans lequel vous essayez d'implémenter une carte avec des clés dupliquées? Je suis sûr qu'il pourrait y avoir une meilleure solution. Les cartes sont destinées à conserver des clés uniques pour une bonne raison. Bien que si vous vouliez vraiment le faire; vous pouvez toujours étendre la classe en écrivant une classe de carte personnalisée simple dotée d'une fonction d'atténuation des collisions et vous permettant de conserver plusieurs entrées avec les mêmes clés. 

Remarque: vous devez implémenter une fonction d'atténuation des collisions de telle sorte que les clés en collision soient converties en un ensemble unique "toujours". Quelque chose de simple comme ajouter une clé avec un hashcode ou quelque chose? 

0
Priyank

S'il existe des clés en double, une clé peut correspondre à plusieurs valeurs. La solution évidente consiste à mapper la clé sur 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
0
cyberthanasis

Avec un peu de piratage, vous pouvez utiliser HashSet avec des clés en double. AVERTISSEMENT: cela dépend fortement de la mise en œuvre de 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);
    }
}
0
Erdem