web-dev-qa-db-fra.com

Est-ce une bonne idée de stocker des données sous forme de clés dans HashMap avec des valeurs vides / nulles?

J'avais à l'origine écrit un ArrayList et stocké des valeurs uniques (noms d'utilisateur, c'est-à-dire Strings) dedans. Plus tard, j'ai dû utiliser le ArrayList pour rechercher si un utilisateur y existait. C'est O(n) pour la recherche.

Mon responsable technique voulait que je change cela en HashMap et que je stocke les noms d'utilisateur sous forme de clés dans le tableau et les valeurs sous vide Strings.

Donc, en Java -

hashmap.put("johndoe","");

Je peux voir si cet utilisateur existe plus tard en exécutant -

hashmap.containsKey("johndoe"); 

C'est O(1) non?

Mon responsable a dit que c'était un moyen plus efficace de le faire et que cela avait du sens pour moi, mais il semblait juste un peu décalé de mettre null/empty en tant que valeurs dans la table de hachage et de stocker des éléments en tant que clés.

Ma question est la suivante: est-ce une bonne approche? L'efficacité bat ArrayList#contains Ou une recherche de tableau en général. Ça marche. Mon inquiétude est que je n'ai vu personne faire cela après une recherche. Je manque peut-être un problème évident quelque part, mais je ne le vois pas.

63
dozer

Puisque vous avez un ensemble de valeurs uniques, un Set est la structure de données appropriée. Vous pouvez placer vos valeurs dans HashSet, une implémentation de l'interface Set.

Mon responsable a dit que c'était un moyen plus efficace de le faire et que cela avait du sens pour moi, mais cela semblait juste un peu décalé de mettre null/empty en tant que valeurs dans la table de hachage et de stocker des éléments en tant que clés.

L'avis du responsable est imparfait. Map n'est pas la bonne abstraction pour cela, Set l'est. Un Map est approprié pour les paires clé-valeur. Mais vous n'avez pas de valeurs, seulement des clés.

Exemple d'utilisation:

Set<String> users = new HashSet<>(Arrays.asList("Alice", "Bob"));

System.out.println(users.contains("Alice"));
// -> prints true

System.out.println(users.contains("Jack"));
// -> prints false

Utiliser un Map serait gênant, car quel devrait être le type des valeurs? Cette question n'a aucun sens dans votre cas d'utilisation, car vous n'avez que des clés, pas des paires clé-valeur. Avec un Set, vous n'avez pas besoin de demander cela, l'utilisation est parfaitement naturelle.

C'est O(1) non?

Oui, la recherche dans un HashMap ou un HashSet est O(1) amorti dans le pire des cas, tandis que la recherche dans un List ou un tableau est O(n) pire cas.


Certains commentaires soulignent qu'un HashSet est implémenté en termes de HashMap. C'est très bien, à ce niveau d'abstraction. Au niveau de l'abstraction de la tâche à accomplir --- pour stocker une collection de noms d'utilisateur uniques, utiliser un ensemble est un choix naturel, plus naturel qu'une carte.

102
janos

C'est essentiellement la façon dont HashSet est implémenté, donc je suppose que vous pouvez dire que c'est une bonne approche. Vous pourriez aussi bien utiliser HashSet au lieu de votre HashMap avec des valeurs vides.

Par exemple :

L'implémentation de HashSet par add est

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

map est le support HashMap et PRESENT est une valeur fictive.

Mon inquiétude est que je n'ai vu personne faire cela après une recherche. Je manque peut-être un problème évident quelque part, mais je ne le vois pas.

Comme je l'ai mentionné, les développeurs du JDK utilisent cette même approche.

37
Eran