web-dev-qa-db-fra.com

Carte de plusieurs clés vers une seule valeur Java

Je pense que ma question est similaire à celle-ci: Comment implémenter une carte avec plusieurs clés? mais avec une différence importante. Dans cette question (si ma compréhension est correcte, faites-le moi savoir si ce n'est pas le cas), les clés devaient toujours être uniques. Je veux avoir une carte sous la forme: MyMap où les clés ne sont pas nécessairement uniques. Si cela n'a pas de sens, je veux essentiellement un tableau à 2 dimensions, mais plutôt que de me référer aux éléments par des coordonnées, je veux les désigner par des paires d'objets.

Quelqu'un a-t-il des idées sur une bibliothèque où cela fonctionne ou sur une bonne façon de l'implémenter moi-même? En ce qui concerne les bibliothèques, j'ai regardé Apache Commons et Guava, ni ne semble avoir ce que je veux.

20
Steve

La structure de données Table dans Guava semble répondre à votre exigence de faire référence à une valeur par une paire d'objets.

18
Mark

J'espère que cette réponse ne sera pas considérée comme une diatribe, mais pour autant que je puisse comprendre, vous voulez utiliser une bibliothèque pour quelque chose que vous pouvez réaliser de manière triviale en utilisant un jdk prêt à l'emploi.

Quoi qu'il en soit, vous avez mentionné que vous souhaitez accéder aux éléments à l'aide d'une paire d'objets. Vous pouvez créer une classe qui contiendra les clés, comme

public class Pair {
  // string represntation of an object
  private final String x; 
  private final String y;

  // ctor, getters...

  public int hashcode() {...}
  public boolean equals(Object other) {...}
}

La méthode hashcode générera le code de hachage pour tous les éléments comprenant (dans ce cas, deux, xet y dans votre cas, mais peut être facilement étendu pour prendre en charge un nombre arbitraire de éléments) et deux clés seront identiques si elles ont les mêmes valeurs pour xet y. Si vos éléments de paire ne sont pas de simples chaînes, il est trivial de dériver une représentation sous forme de chaîne de presque n'importe quel objet (fournissez une implémentation décente de la méthode toString, par exemple).

L'idée est d'avoir une représentation de chaîne unique pour chaque élément de la paire.

Bien sûr, la génération de codes de hachage solides n'est pas anodine, donc une excellente option est d'utiliser des chaînes. Pour générer un code de hachage, vous devez simplement ajouter les représentations de chaîne de vos objets paire:

public int hashcode() {
  return ('x' + x + ":y" + y).hashcode();
}

Assurez-vous de fournir un séparateur. Sinon, pour des valeurs telles que x=ab, y=b, et x=a, y=bb, vous obtiendrez le même hashcode, même si les objets sont complètement différents.

Et l'égalité est aussi triviale que d'inspecter la valeur des éléments de la paire:

public boolean equals(Object other) {
  // if other is not null and is an instance of Pair
  final Pair otherPair = (Pair)other;
  return this.x.equals(otherPair.x) && this.y.equals(otherPair.y);
}

Donc, vous pouvez maintenant utiliser votre Pairclass dans une carte, comme dans:

final Map<Pair, Whatever> map = new Hashmap<Pair, Whatever>();
// ...

Fondamentalement, une table de hachage fonctionne en utilisant le code de hachage des clés pour déterminer dans quel compartiment la valeur doit être allouée. Si deux clés ont le même hashcode, la méthode equals sera utilisée pour déterminer si une collision vient de se produire, ou si c'est juste la clé même.

Si vous souhaitez utiliser votre classe Pair dans une TreeMap, vous devez implémenter la méthode compareTo ou fournir votre propre Comparator lors de l'instanciation d'une telle carte. Les implémentations TreeMap s'appuient sur le résultat de la méthode compareTo pour déterminer où une valeur doit être allouée.

13
chahuistle

Apache Commons Collections a MultiKey .

import org.Apache.commons.collections4.keyvalue.MultiKey;

Map<MultiKey, ValueType> myMap = new HashMap<MultiKey, ValueType>();
myMap.put(new MultiKey(key1, key2), value);

myMap.get(new MultiKey(key1, key2));

Il a l'avantage de créer des tableaux à N dimensions à partir d'une carte.

3
adkisson

Il me semble que vous recherchez un HashMap imbriqué. Cela pourrait fonctionner, mais mon instinct dit que la mise en œuvre d'un tel monstre serait une idée terrible, à la fois en termes de performances et de raison.

Comment l'initialiser:

    HashMap<Key1, HashMap<Key2, Value>> nestedHashMap = new HashMap<Key1, HashMap<Key2, Value>>();

Ajout de valeurs:

    Key1 first;
    Key2 second;
    Value data;
    HashMap<Key2, Value> tempMap = new HashMap<Key2, Value>();
    tempMap.put(second, data);
    nestedHashMap.put(first, tempMap);

Récupération des données:

    Key1 first;
    Key2 second;
    Value data;
    data = nestedHashMap.get(first).get(second);

Avis de non-responsabilité: ce code n'a pas été testé, il vient de sortir du haut de ma tête.

2
rjacks