Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Hash "réciproque" d'une liste

4 réponses
Avatar
Eric C.
Bonjour =E0 tous (=E7a ne me rajeunit pas, la derni=E8re fois que j'ai post=
=E9
dans ce groupe, d'apr=E8s Google, c'=E9tait en avril 2001 ...), j'ai une
question plus "esth=E9tique" qu'autre chose : comment construire le plus
simplement possible le hash "r=E9ciproque" d'une liste ? Si la liste
associe des valeurs aux indices, ce hash doit associer les indices aux
valeurs. Petit exemple pour illustrer :
@tab=3D("a","b","c","d");
$length=3D@tab;
for ($i=3D0;$i<$length;$i++) {
$my_hash{$tab[$i]}=3D$i;
}
J'imagine que =E7a doit pouvoir s'=E9crire en une ligne, mais je n'ai rien
trouv=E9 ...


Eric

4 réponses

Avatar
Paul Gaborit
À (at) Tue, 1 Jun 2010 05:59:09 -0700 (PDT),
"Eric C." écrivait (wrote):

Bonjour à tous (ça ne me rajeunit pas, la dernière fois que j'ai posté
dans ce groupe, d'après Google, c'était en avril 2001 ...),



Bonjour,

j'ai une
question plus "esthétique" qu'autre chose : comment construire le plus
simplement possible le hash "réciproque" d'une liste ? Si la liste
associe des valeurs aux indices, ce hash doit associer les indices aux
valeurs. Petit exemple pour illustrer :
@tab=("a","b","c","d");
$length=@tab;
for ($i=0;$i<$length;$i++) {
$my_hash{$tab[$i]}=$i;
}
J'imagine que ça doit pouvoir s'écrire en une ligne, mais je n'ai rien
trouvé ...



En supposant que les valeurs sont uniques (bijection indice <-> valeur)
alors votre code est correct. On peut l'écrire de manière un tout petit
peu plus "perlienne" (mais pas obligatoirement plus efficace -- il
faudrait faire un benchmark) :

my @tab = "a" .. "z";
my %my_hash = map {($tab[$_] => $_)} 0..$#tab;

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>
Avatar
Eric C.
On 1 juin, 15:18, Paul Gaborit wrote:


En supposant que les valeurs sont uniques (bijection indice <-> valeur)
alors votre code est correct. On peut l' crire de mani re un tout petit
peu plus "perlienne" (mais pas obligatoirement plus efficace -- il
faudrait faire un benchmark) :

  my @tab = "a" .. "z";
  my %my_hash = map {($tab[$_] => $_)} 0..$#tab;



Merci, je me doutais qu'il y avait une solution par map, mais mon perl
étant un peu rouillé ça n'était pas (re)venu.
Niveau lisibilité, difficile de dire quelle solution est la plus
compréhensible ...
Je n'avais effectivement pas pensé à une éventuelle non-bijectivité
(je n'ai pas ce problème, les valeurs sont des noms de colonnes
obligatoirement différents).

En tout cas je constate que les mêmes anges gardiens veillent encore
et toujours sur le ng :)

Eric
Avatar
Jerome Quelin
Paul Gaborit wrote:
J'imagine que ça doit pouvoir s'écrire en une ligne, mais je n'ai rien
trouvé ...



En supposant que les valeurs sont uniques (bijection indice <-> valeur)
alors votre code est correct. On peut l'écrire de manière un tout petit
peu plus "perlienne" (mais pas obligatoirement plus efficace -- il
faudrait faire un benchmark) :

my @tab = "a" .. "z";
my %my_hash = map {($tab[$_] => $_)} 0..$#tab;



ou en utilisant des tranches de hash :
my %hash;
@hash{ @tab } = 0..$#tab;

jérôme
--

Avatar
Paul Gaborit
À (at) Thu, 03 Jun 2010 17:03:18 +0200,
Jerome Quelin écrivait (wrote):

Paul Gaborit wrote:
J'imagine que ça doit pouvoir s'écrire en une ligne, mais je n'ai rien
trouvé ...



En supposant que les valeurs sont uniques (bijection indice <-> valeur)
alors votre code est correct. On peut l'écrire de manière un tout petit
peu plus "perlienne" (mais pas obligatoirement plus efficace -- il
faudrait faire un benchmark) :

my @tab = "a" .. "z";
my %my_hash = map {($tab[$_] => $_)} 0..$#tab;



ou en utilisant des tranches de hash :
my %hash;
@hash{ @tab } = 0..$#tab;



J'ai fait un petit benchmark pour voir et le résultat est sans appel :

Benchmark: timing 500000 iterations of foreach, map, slice...
foreach: 9.46806 wallclock secs ( 8.67 usr + 0.04 sys = 8.71 CPU)
@ 57405.28/s (nP0000)
map: 13.4544 wallclock secs (12.75 usr + 0.03 sys = 12.78 CPU)
@ 39123.63/s (nP0000)
slice: 6.38025 wallclock secs ( 6.05 usr + 0.02 sys = 6.07 CPU)
@ 82372.32/s (nP0000)

Il vaut donc mieux passer par les tranches de hash !

Pour ceux que ça intéresse, voici le code du benchmark :
############################
use Benchmark qw(:hireswallclock);

my @tab = "a" .. "z";

timethese(500000,
{
'map' => sub {
my %my_hash = map {($tab[$_] => $_)} 0..$#tab;
},
'foreach' => sub {
my %hash;
foreach (0..$#tab) {
$hash{$tab[$_]} = $_;
}
},
'slice' => sub {
my %hash;
@hash{ @tab } = 0..$#tab;
},
}
);
############################


--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>