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

StackOverflow https://stackoverflow.com/questions/95820

  •  01-07-2019
  •  | 
  •  

Question

Supposons que j'ai un tableau et que je sais que je vais faire beaucoup de choses "Le tableau contient-il X?" chèques. Pour ce faire, le moyen le plus efficace consiste à transformer ce tableau en un hachage, où les clés sont les éléments du tableau, puis 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.

Était-ce utile?

La solution

%hash = map { <*>

Ce n'est pas aussi court que le " @hash {@array} = ... " solutions, mais celles-ci nécessitent que le hachage et le tableau soient déjà définis ailleurs, alors que celui-ci peut prendre un tableau anonyme et renvoyer un hachage anonyme.

Cela permet de prendre chaque élément du tableau et de le coupler avec un "1". Lorsque cette liste de paires (clé, 1, clé, 1, clé 1) est affectée à un hachage, les paires impaires deviennent les clés du hachage et les paires paires deviennent les valeurs respectives.

=> 1 } @array;

Ce n'est pas aussi court que le " @hash {@array} = ... " solutions, mais celles-ci nécessitent que le hachage et le tableau soient déjà définis ailleurs, alors que celui-ci peut prendre un tableau anonyme et renvoyer un hachage anonyme.

Cela permet de prendre chaque élément du tableau et de le coupler avec un "1". Lorsque cette liste de paires (clé, 1, clé, 1, clé 1) est affectée à un hachage, les paires impaires deviennent les clés du hachage et les paires paires deviennent les valeurs respectives.

Autres conseils

 @hash{@array} = (1) x @array;

Il s’agit d’une tranche de hachage, une liste de valeurs issues du hachage, de sorte qu’elle place la liste-y @ devant.

De la documentation :

  

Si vous ne savez pas pourquoi vous utilisez   un "@" sur une tranche de hachage à la place   d'un '%', pense comme ça. le   type de support (carré ou bouclé)   régit que ce soit un tableau ou un   hash étant regardé. De l'autre   hand, le symbole principal ('$' ou '@')   sur le tableau ou le hachage indique si   vous récupérez une valeur singulière   (un scalaire) ou un pluriel (une liste).

@hash{@keys} = undef;

La syntaxe ici où vous vous référez au hachage avec un @ est une tranche de hachage. Nous disons en gros $ hash {$ keys [0]} ET $ hash {$ keys [1]} ET $ hash {$ keys [2] } ... est une liste sur le côté gauche de =, une lvalue, et nous l'attribuons à cette liste, qui entre dans le hachage et définit les valeurs de toutes les clés nommées. Dans ce cas, je n'ai spécifié qu'une seule valeur, de sorte que cette valeur entre dans $ hash {$ keys [0]} , et les autres entrées de hachage toutes s'animent automatiquement (deviennent actives) avec des valeurs indéfinies. [Ma suggestion initiale consistait à définir l'expression = 1, ce qui aurait défini cette clé sur 1 et les autres sur undef . Je l'ai modifié pour des raisons de cohérence, mais comme nous le verrons ci-dessous, les valeurs exactes importent peu.]

Lorsque vous réalisez que la lvalue, l'expression du côté gauche du =, est une liste construite à partir du hachage, vous comprendrez pourquoi nous utilisons ce code @ . [Sauf que je pense que cela va changer dans Perl 6.]

L’idée ici est que vous utilisez le hachage comme un ensemble. Ce qui compte, ce n’est pas la valeur que j’attribue; c'est juste 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

à la place:

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

Il est en fait plus efficace de simplement exécuter une vérification exist que de se préoccuper de la valeur dans le hachage, bien que pour moi l'important soit simplement le concept que vous représentez un ensemble avec clés du hash. En outre, quelqu'un a fait remarquer qu'en utilisant undef comme valeur ici, nous allons utiliser moins d'espace de stockage que nous allions attribuer une valeur. (Et génèrent également moins de confusion, car la valeur n'a pas d'importance, et ma solution attribuerait une valeur uniquement au premier élément du hachage et laisserait les autres undef . construire un tableau de valeurs pour aller dans le hachage; effort complètement gaspillé).

Notez que si vous tapez si (existe $ hash {clé}) 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’un clé plutôt que la véracité de sa valeur), alors vous pouvez utiliser le court et doux

@hash{@key} = ();

Il existe un présupposé, à savoir que le moyen le plus efficace de faire beaucoup de choses "Le tableau contient-il X?" vérifie est de convertir le tableau en un hachage. L'efficacité dépend de la ressource rare, souvent du temps mais parfois de l'espace et parfois du travail du programmeur. Vous doublez au moins la quantité de mémoire utilisée en conservant simultanément une liste et un hachage de la liste. De plus, vous écrivez plus de code original que vous aurez besoin de tester, de documenter, etc.

Vous pouvez également consulter le module List :: MoreUtils, plus précisément les fonctions any () , none () , true () et false () . Ils prennent tous un bloc comme conditionnel et une liste comme argument, comme pour map () et grep () :

print " Au moins une valeur indéfinie " si tout {! defini ($ _)} @list;

J'ai effectué un test rapide, chargeant la moitié de / usr / share / dict / words dans un tableau (25 000 mots), puis recherchant onze mots sélectionnés dans l'ensemble du dictionnaire (tous les 5 000 mots) du tableau, en utilisant La méthode array-to-hash et la fonction any () de List :: MoreUtils.

Sous Perl 5.8.8 construit à partir des sources, la méthode array-to-hash s'exécute presque 1100 fois plus vite que la méthode any () (1300 fois plus vite sous Perl 5.8.7 empaqueté dans Ubuntu 6.06. )

Ce n'est pas tout, cependant - la conversion de matrice à hachage prend environ 0,04 seconde, ce qui dans ce cas tue l'efficacité temporelle de la méthode de matrice à hachage à 1,5 x 2x plus rapide que le any () méthode. Toujours bon, mais pas aussi stellaire.

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

J'ai toujours pensé que

foreach my $item (@array) { $hash{$item} = 1 }

était au moins agréable et lisible / maintenable.

Dans Perl 5.10, il y a l'opérateur ~~ presque magique:

sub invite_in {
    my $vampires = [ qw(Angel Darla Spike Drusilla) ];
    return (

Dans Perl 5.10, il y a l'opérateur ~~ presque magique:

<*>

Voir ici: http: //dev.perl. org / perl5 / news / 2007 / perl-5.10.0.html

[0] ~~ $vampires) ? 0 : 1 ; }

Voir ici: http: //dev.perl. org / perl5 / news / 2007 / perl-5.10.0.html

Il convient également de noter que, pour être complet, ma méthode habituelle consiste à utiliser deux tableaux de même longueur @keys et @vals , ce que vous préférez être un hachage ...

mon% hash = map {$ keys [$ _] = > $ vals [$ _]} (0 .. @ keys-1);

La solution de Raldi peut être réduite à ceci (le '= >' de l'original n'est pas nécessaire):

my %hash = map { 

La solution de Raldi peut être réduite à ceci (le '= >' de l'original n'est pas nécessaire):

my %hash = map { 

La solution de Raldi peut être réduite à ceci (le '= >' de l'original n'est pas nécessaire):

my %hash = map { 

La solution de Raldi peut être réduite à ceci (le '= >' de l'original n'est pas nécessaire):

my %hash = map { split("=",

La solution de Raldi peut être réduite à ceci (le '= >' de l'original n'est pas nécessaire):

my %hash = map { 

La solution de Raldi peut être réduite à ceci (le '= >' de l'original n'est pas nécessaire):

my %hash = map { 

La solution de Raldi peut être réduite à ceci (le '= >' de l'original n'est pas nécessaire):

my %hash = map { 

La solution de Raldi peut être réduite à ceci (le '= >' de l'original n'est pas nécessaire):

my %hash;
#The values in %hash can only be accessed by doing exists($hash{$key})
#The assignment only works with '= undef;' and will not work properly with '= 1;'
#if you do '= 1;' only the hash key of $array[0] will be set to 1;
@hash{@array} = undef;

Cette technique peut également être utilisée pour transformer des listes de texte en hachages:

<*>

De plus, si vous avez une ligne de valeurs comme celle-ci: "toto = 1, bar = 2, baz = 3". vous pouvez faire ceci:

<*>

[MODIFIER pour inclure]

Une autre solution proposée (qui prend deux lignes) est la suivante:

<*>,1 } @array;

Cette technique peut également être utilisée pour transformer des listes de texte en hachages:

<*>

De plus, si vous avez une ligne de valeurs comme celle-ci: "toto = 1, bar = 2, baz = 3". vous pouvez faire ceci:

<*>

[MODIFIER pour inclure]

Une autre solution proposée (qui prend deux lignes) est la suivante:

<*>,1 } split(",",$line)

Cette technique peut également être utilisée pour transformer des listes de texte en hachages:

<*>

De plus, si vous avez une ligne de valeurs comme celle-ci: "toto = 1, bar = 2, baz = 3". vous pouvez faire ceci:

<*>

[MODIFIER pour inclure]

Une autre solution proposée (qui prend deux lignes) est la suivante:

<*>,1 } @array;

Cette technique peut également être utilisée pour transformer des listes de texte en hachages:

<*>

De plus, si vous avez une ligne de valeurs comme celle-ci: "toto = 1, bar = 2, baz = 3". vous pouvez faire ceci:

<*>

[MODIFIER pour inclure]

Une autre solution proposée (qui prend deux lignes) est la suivante:

<*>) } split(",",$line);

Cette technique peut également être utilisée pour transformer des listes de texte en hachages:

<*>

De plus, si vous avez une ligne de valeurs comme celle-ci: "toto = 1, bar = 2, baz = 3". vous pouvez faire ceci:

<*>

[MODIFIER pour inclure]

Une autre solution proposée (qui prend deux lignes) est la suivante:

<*>,1 } @array;

Cette technique peut également être utilisée pour transformer des listes de texte en hachages:

<*>

De plus, si vous avez une ligne de valeurs comme celle-ci: "toto = 1, bar = 2, baz = 3". vous pouvez faire ceci:

<*>

[MODIFIER pour inclure]

Une autre solution proposée (qui prend deux lignes) est la suivante:

<*>,1 } split(",",$line)

Cette technique peut également être utilisée pour transformer des listes de texte en hachages:

<*>

De plus, si vous avez une ligne de valeurs comme celle-ci: "toto = 1, bar = 2, baz = 3". vous pouvez faire ceci:

<*>

[MODIFIER pour inclure]

Une autre solution proposée (qui prend deux lignes) est la suivante:

<*>,1 } @array;

Cette technique peut également être utilisée pour transformer des listes de texte en hachages:

<*>

De plus, si vous avez une ligne de valeurs comme celle-ci: "toto = 1, bar = 2, baz = 3". vous pouvez faire ceci:

<*>

[MODIFIER pour inclure]

Une autre solution proposée (qui prend deux lignes) est la suivante:

<*>

Vous pouvez également utiliser Perl6 :: Junction .

use Perl6::Junction qw'any';

my @arr = ( 1, 2, 3 );

if( any(@arr) == 1 ){ ... }

Si vous effectuez de nombreuses opérations théoriques sur les ensembles, vous pouvez également utiliser Set :: Scalar ou un module similaire. Ensuite, $ s = Set :: Scalar- & new (@array) construira le Set pour vous - et vous pourrez l'interroger avec: $ s- > contient ($ m) .

Vous pouvez placer le code dans un sous-programme si vous ne voulez pas polluer votre espace de noms.

my $hash_ref =
  sub{
    my %hash;
    @hash{ @{[ qw'one two three' ]} } = undef;
    return \%hash;
  }->();

Ou même mieux:

sub keylist(@){
  my %hash;
  @hash{@_} = undef;
  return \%hash;
}

my $hash_ref = keylist qw'one two three';

# or

my @key_list = qw'one two three';
my $hash_ref = keylist @key_list;

Si vous voulez vraiment passer une référence à un tableau:

sub keylist(\@){
  my %hash;
  @hash{ @{

Vous pouvez placer le code dans un sous-programme si vous ne voulez pas polluer votre espace de noms.

my $hash_ref =
  sub{
    my %hash;
    @hash{ @{[ qw'one two three' ]} } = undef;
    return \%hash;
  }->();

Ou même mieux:

sub keylist(@){
  my %hash;
  @hash{@_} = undef;
  return \%hash;
}

my $hash_ref = keylist qw'one two three';

# or

my @key_list = qw'one two three';
my $hash_ref = keylist @key_list;

Si vous voulez vraiment passer une référence à un tableau:

<*>[0]} } = undef if @_; return \%hash; } my @key_list = qw'one two three'; my $hash_ref = keylist @key_list;

Vous pouvez également consulter Cravate :: IxHash , qui implémente des tableaux associatifs ordonnés. Cela vous permettrait de faire les deux types de recherches (hachage et index) sur une copie de vos données.

#!/usr/bin/perl -w

use strict;
use Data::Dumper;

my @a = qw(5 8 2 5 4 8 9);
my @b = qw(7 6 5 4 3 2 1);
my $h = {};

@{$h}{@a} = @b;

print Dumper($h);

donne (notez que les touches répétées obtiennent la valeur à la position la plus grande du tableau - c'est-à-dire 8- > 2 et non 6)

$VAR1 = {
          '8' => '2',
          '4' => '3',
          '9' => '1',
          '2' => '5',
          '5' => '4'
        };
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top