82 votes

En Perl, comment créer un hachage dont les clés proviennent d'un tableau donné?

Disons que j'ai un tableau, et je sais que je vais faire beaucoup de "Est-ce que le tableau contient X?" chèques. Pour ce faire, le moyen le plus efficace est de transformer ce tableau en hachage, où les clés sont les éléments du tableau, et vous pouvez simplement dire

 if ($ hash {X}) {...} 

Existe-t-il un moyen simple d'effectuer cette conversion de tableau à hachage? Idéalement, il devrait être suffisamment polyvalent pour prendre un tableau anonyme et renvoyer un hachage anonyme.

123voto

raldi Points 5114
%hash = map { $_ => 1 } @array;

Ce n'est pas aussi court que le "@hash{@array} = ..." des solutions, mais celles-ci exigent l'utilisation et le tableau d'ores et déjà être défini quelque part d'autre, alors que celui-ci peut prendre un anonyme, un tableau et retourne un anonyme de hachage.

Ce qu'il fait est de prendre chaque élément du tableau et de le coupler avec un "1". Lorsque cette liste de (clé, 1 clé, 1, 1) paires sont attribuées à une table de hachage, le impaires ceux devenir le hachage de touches, et les paires dernières deviennent les valeurs respectives.

43voto

moritz Points 6295
 @hash{@array} = (1) x @array;

C'est un hash d'une tranche, d'une liste de valeurs à partir de la table de hachage, il obtient la liste-y @ devant.

À partir de la documentation:

Si vous êtes confus au sujet de pourquoi vous utilisez un '@', il y a sur une table de hachage tranche au lieu d'un '%', pensez-y comme ça. L' type de support (carré ou bouclés) détermine si c'est un tableau ou une hachage d'être regardé. Sur l'autre la main, le premier symbole ('$' ou '@') sur le tableau ou de hachage indique si vous obtenez en retour une valeur singulière (un scalaire) ou d'un pluriel (dans une liste).

40voto

skiphoppy Points 16563
@hash{@keys} = undef;

La syntaxe ici où vous faites référence à la valeur de hachage avec un @ est un hachage de la tranche. Nous sommes fondamentalement en disant $hash{$keys[0]} ET $hash{$keys[1]} ET $hash{$keys[2]} ... une liste sur le côté gauche de l' =, une lvalue, et nous attribuons à cette liste, qui en fait va dans la table de hachage et définit les valeurs pour toutes les clés nommées. Dans ce cas, je ne l'ai spécifié une valeur, de sorte que la valeur va en $hash{$keys[0]}, et l'autre de hachage entrées de tous les auto-vivifier (vie) avec une valeur non définie. [Ma suggestion ici est de définir l'expression = 1, ce qui aurait mis la clé à 1 et les autres à l' undef. Je l'ai changé pour des raisons de cohérence, mais, comme nous allons le voir ci-dessous, les valeurs exactes n'ont pas d'importance.]

Lorsque vous vous rendez compte que la lvalue, l'expression sur le côté gauche de l' =, une liste construit à partir de la table de hachage, puis il va commencer à effectuer un certain sens, pourquoi nous utilisons @. [Sauf que je pense que cela va changer en Perl 6.]

L'idée ici est que vous êtes à l'aide de la table de hachage comme un ensemble. Ce qui importe, ce n'est pas la valeur que je suis affectation; c'est seulement l'existence des clés. Donc, ce que vous voulez faire n'est pas quelque chose comme:

if ($hash{$key} == 1) # then key is in the hash

au lieu de cela:

if (exists $hash{$key}) # then key is in the set

C'est en fait plus efficace de simplement lancer une exists , que de s'embêter avec la valeur dans la table de hachage, bien que pour moi, l'important, ici, c'est juste le concept qui vous êtes représentant d'un jeu juste avec les touches de la table de hachage. Aussi, quelqu'un a souligné que par l'aide d' undef la valeur ici, nous permettra de consommer moins d'espace de stockage que nous ne l'affectation d'une valeur. (Et aussi de générer moins de confusion, que la valeur n'a pas d'importance, et ma solution serait d'attribuer une valeur uniquement le premier élément dans la table de hachage et de laisser les autres undef, et certains autres solutions sont en tournant la roue pour construire un tableau de valeurs d'aller dans la table de hachage; complètement perdu l'effort).

16voto

Aristotle Pagaltzis Points 43253

Notez que si taper if ( exists $hash{ key } ) n’est pas trop de travail pour vous (que je préfère utiliser car la question d’intérêt est vraiment la présence d’une clé plutôt que la vérité de sa valeur), alors vous pouvez utiliser le court et doux

 @hash{@key} = ();
 

7voto

arclight Points 499

Il y a un présupposé ici, que le moyen le plus efficace pour faire beaucoup de "le tableau contient X?" contrôles est de convertir le tableau de hachage. L'efficacité dépend de la ressource rare, souvent le temps, mais parfois, et parfois programmeur effort. Vous avez au moins le doublement de la mémoire consommée en gardant une liste et un hachage de la liste autour simultanément. Plus vous écrivez, plus original le code que vous aurez besoin de tester, document, etc.

Comme une alternative, regarde la Liste::MoreUtils module, dont les fonctions any(), none(), true() et false(). Ils prennent tous un bloc comme le conditionnel et une liste en argument, semblable à de la map() et grep():

print "At least one value undefined" if any { !defined($_) } @list;

J'ai couru un test rapide, le chargement dans la moitié de /usr/share/dict/words dans un tableau (25000 mots), puis la recherche de onze mots sélectionnés à travers le dictionnaire complet (tous les 5 000ème mot) dans le tableau, à l'aide de la matrice-à-méthode de hachage et l' any() fonction de la Liste::MoreUtils.

Sur Perl 5.8.8 construit à partir de la source, le tableau de hachage méthode fonctionne presque 1100x plus rapide que l' any() méthode (1300x plus vite sous Ubuntu 6.06 est emballé Perl 5.8.7.)

Ce n'est pas l'histoire complète cependant - le tableau de hachage de conversion prend environ 0,04 secondes qui, dans ce cas, tue le temps l'efficacité de la baie de méthode de hachage à 1,5 x 2x plus rapide que l' any() méthode. Encore bonne, mais pas aussi stellaire.

Mon sentiment est que la matrice-à-méthode de hachage va battre any() dans la plupart des cas, mais je me sentirais beaucoup mieux si j'avais un peu plus solide métriques (beaucoup de cas de test, décent analyses statistiques, peut-être que certains grands-O algorithmique analyse de chaque méthode, etc.) En fonction de vos besoins, de la Liste::MoreUtils peut être une meilleure solution; il est certainement plus souple et nécessite moins de codage. Rappelez-vous, l'optimisation prématurée est un péché... :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X