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

Tri de hash ?

8 réponses
Avatar
ctobini
Bonjour,

J'aurais une petite question concernant les hashages :

Soit un hash :

$a =3D {};
$a->{'val1'}->{'unit1'} =3D 5;
$a->{'val1'}->{'unit2'} =3D 1;
$a->{'val1'}->{'unit3'} =3D 8;

Y aurait-il moyen de lire les =E9l=E9ments de ce hash en les triant selon
la valeurs des 'unit', afin d'avoir en sortie :

val1 unit2 1
val1 unit1 5
val1 unit3 8

J'ai suivi un tutoriel, mais je dois m'emmeler les pinceaux dans les
foreach.

En vous remerciant.

C=2E Tobini

8 réponses

Avatar
Jacques Caron
Salut,

On Thu, 02 Feb 2006 19:02:27 +0100, ctobini wrote:

Bonjour,

J'aurais une petite question concernant les hashages :

Soit un hash :

$a = {};
$a->{'val1'}->{'unit1'} = 5;
$a->{'val1'}->{'unit2'} = 1;
$a->{'val1'}->{'unit3'} = 8;

Y aurait-il moyen de lire les éléments de ce hash en les triant selon
la valeurs des 'unit', afin d'avoir en sortie :

val1 unit2 1
val1 unit1 5
val1 unit3 8


Tous les éléments, ou juste ceux "à l'intérieur" de val1? Dans le dernier
cas (et en appelant le hashref $h plutôt que $a):

sub printsortedhash
{
my $v = shift;
my $h = shift;

print map {"$v $_ $h->{$_}n"} sort {$h->{$a} <=> $h->{$b}} keys %$h;
}

printsortedhash("val1",$h->{val1});

Pas testé, mais ça doit pas être loin.

Si tu veux toutes les valeurs, c'est un peu plus compliqué, va falloir
mettre tout ça à plat:

my $tmp_h = { map { my $i = $_; map { ("$i $_" => $h->{$i}{$_}) } keys
%{$h->{$i}} } keys %$h };

print map {"$_ $tmp_h->{$_}n"} sort {$tmp_h->{$a} <=> $tmp_h->{$b}} keys
%$tmp_h;

C'est peut-être jouable en une seule "ligne" (sans passer par un hash
intermédiaire) mais j'avoue que j'ai la flemme...

Jacques.
--
Oxado http://www.oxado.com/

Avatar
Paul Gaborit
À (at) 2 Feb 2006 10:02:27 -0800,
"ctobini" écrivait (wrote):
J'aurais une petite question concernant les hashages :

Soit un hash :

$a = {};
$a->{'val1'}->{'unit1'} = 5;
$a->{'val1'}->{'unit2'} = 1;
$a->{'val1'}->{'unit3'} = 8;


$a et $b sont deux noms de variables réservés (pour les tris !).
Changeons donc de nom et écrivons plus simplement :

$h = {
val1 => {
unit1 => 5,
unit2 => 1,
unit3 => 8,
},
val2 => {
b => 3,
c => 7,
},
};

Y aurait-il moyen de lire les éléments de ce hash en les triant selon
la valeurs des 'unit', afin d'avoir en sortie :

val1 unit2 1
val1 unit1 5
val1 unit3 8


Si vous ne souhaitez que ce second niveau ('val1' est connu et
constant) :

foreach my $key (sort
{$h->{val1}{$a} <=> $h->{val1}{$b}}
keys %{$a->{val1}}) {
print "$key $a->{val1}{$key}n";
}

Résultat :

unit2 1
unit1 5
unit3 8

Si vous souhaitez trier par valeurs sur toutes les clés des deux
niveaux, c'est un peu plus sioux et sûrement moins lisible :

foreach my $bc (sort
{$h->{$a->[0]}{$a->[1]}
<=>
$h->{$b->[0]}{$b->[1]}}
map {
my $k = $_;
(map {[$k, $_]} keys %{$h->{$k}})
} keys %{$h}) {
print "$bc->[0]t$bc->[1]t$h->{$bc->[0]}{$bc->[1]}n";
}

Résultat :

val1 unit2 1
val2 b 3
val1 unit1 5
val2 c 7
val1 unit3 8

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

Avatar
ctobini
Bonjour à tous et merci pour vos réponses,

J'ai testé les différentes formes, notamment la 'sioux' que j'ai bien
apprécié.

Je me retrouve devant un autre problème :

Le hash que je vous ai indiqué est simplifié par rapport à celui que
j'ai réellement, en fait la forme est du style :

$h->{'a'}->{'b'}->{'c'}->{'val'} = 5;
$h->{'a'}->{'b'}->{'c'}->{'rap'} = 12;
$h->{'a'}->{'b'}->{'c'}->{'for'} = 66;
$h->{'a'}->{'b'}->{'c'}->{'rat'} = 78;
$h->{'a'}->{'b'}->{'c'}->{'mlp'} = 89;

Je voudrais effectuer un tri à partir de 'c', ce que j'ai fait avec
votre aide, le problème étant que je voudrais trier 'c' en fonction
de 'rat', or j'effectue un tri selon toutes les valeurs.

Sauriez-vous comment je peux m'y prendre pour ne prendre en compte que
'rat' dans le tri des valeurs ?

Merci.

C. Tobini
Avatar
Paul Gaborit
À (at) 3 Feb 2006 07:57:13 -0800,
"ctobini" écrivait (wrote):
Je me retrouve devant un autre problème :

Le hash que je vous ai indiqué est simplifié par rapport à celui que
j'ai réellement, en fait la forme est du style :

$h->{'a'}->{'b'}->{'c'}->{'val'} = 5;
$h->{'a'}->{'b'}->{'c'}->{'rap'} = 12;
$h->{'a'}->{'b'}->{'c'}->{'for'} = 66;
$h->{'a'}->{'b'}->{'c'}->{'rat'} = 78;
$h->{'a'}->{'b'}->{'c'}->{'mlp'} = 89;


Les flêches sont (prseque) toujours inutiles après une accolade ou un
crocher fermants. On peut donc écrire :

$h->{'a'}{'b'}{'c'}{'mlp'} = 89;

Les quotes ou guillemets sont inutiles si on utilise un mot simple
comme clé. On peut donc écrire :

$h->{a}{b}{c}{mlp} = 89;

Je voudrais effectuer un tri à partir de 'c', ce que j'ai fait avec
votre aide, le problème étant que je voudrais trier 'c' en fonction
de 'rat', or j'effectue un tri selon toutes les valeurs.

Sauriez-vous comment je peux m'y prendre pour ne prendre en compte que
'rat' dans le tri des valeurs ?


Votre demande n'est pas claire... Sans plus de précision, on ne peut
que vous renvoyer vers les différents exemples de codes que nous vous
avons déjà fournis. À vous de les adapter à votre besoin.

La démarche générale est relativement simple :

1 - identifiez les informations que vous voulez trier.

2 - identifiez le critère de tri de ces informations.

3 - réussir à produire une liste non triée de ces informations (par
exemples les valeurs d'un tableau) ou de quelque chose qui permet
de retrouver cette information (l'indice, la clé d'accès ou
peut-être dans votre cas, la liste des clés d'accès).

4 - passer cette liste à travers 'sort' en lui indiquant la
fonction de tri à appliquer.

Or dans votre demande, le point 1 n'est pas clair du tout. Pour le
point 2, vous dites vouloir utiliser la valeur attachée à la clé
'rat'. Les points 3 et 4 ne sont que des techniques de programmation
pour lesquelles on ne peut vous aider que si 1 et 2 sont déjà
clairement définis.


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

Avatar
ctobini
Bonjour,

Effectivement, c'est un peu fouilli (désolé) vu que la boucle que je
donne en exemple est imbriquée dans une autre boucle car le tableau
asser grand, avec différents agencement de clés. Je vais essayer
d'être plus clair.

$h = {};

# mon but est de classer unit11 selon la valeur rattachée à rat
$h{val1}{unit11}{1}{rat} = 5;
$h{val1}{unit11}{1}{ooo} = 3;
$h{val1}{unit11}{1}{iii} = 6;
$h{val1}{unit11}{1}{ppp} = 4;

$h{val1}{unit11}{2}{rat} = 2;
$h{val1}{unit11}{2}{ooo} = 1;
$h{val1}{unit11}{2}{iii} = 5;
$h{val1}{unit11}{2}{ppp} = 105;

# j'ai plusieurs critères de tri, et je 'raccroche' le tri que je
voudrais effectuer à partir de $k3 car les boucles concernant $k et
$k2 servent dans une boucle principale.
foreach $k (keys %{$h}) { #ici val1
foreach $k2 (keys %{$h->{$k}}) { #ici unit11
# ici le tri que je voudrais effectuer -> unit11 classé selon 'rat'
# la méthode que vous m'avez indiquée fait effectivement le
classement que je souhaite, mais sur la totalité des valeurs suivant
les clés rattachées à unit11
foreach my $k3 ( sort
{ $h->{$k}->{$k2}->{$a->[0]}->{$a->[1]} <=>
$h->{$k}->{$k2}->{$b->[0]}->{$b->[1]} }
map { $t = $_; (map{[$t, $_]} keys
%{$h->{$k}->{$k2}->{$t}}) }
keys %{$h->{$k}->{$k2}}) {
print "$k3->[0] $k3->[1]
".$h->{$k}->{$k2}->{$k3->[0]}->{$k3->[1]}."n";
}
}
}

Ce que je voudrais, c'est en fait à partir de $k3, indiquer que c'est
'rat' qui détermine le trie, or, en passant par keys(), je ne vois pas
comment obtenir uniquement la valeur de 'rat' comme critère.

Encore désolé et merci du coup de main.

C. Tobini
Avatar
Paul Gaborit
À (at) 6 Feb 2006 03:51:06 -0800,
"ctobini" écrivait (wrote):
Effectivement, c'est un peu fouilli (désolé) vu que la boucle que je
donne en exemple est imbriquée dans une autre boucle car le tableau
asser grand, avec différents agencement de clés. Je vais essayer
d'être plus clair.

$h = {};

# mon but est de classer unit11 selon la valeur rattachée à rat
$h{val1}{unit11}{1}{rat} = 5;


Là, vous avez supprimé une flêche de trop ;-)

$h->{val1}{unit11}{1}{rat} = 5;

$h{val1}{unit11}{1}{ooo} = 3;
$h{val1}{unit11}{1}{iii} = 6;
$h{val1}{unit11}{1}{ppp} = 4;

$h{val1}{unit11}{2}{rat} = 2;
$h{val1}{unit11}{2}{ooo} = 1;
$h{val1}{unit11}{2}{iii} = 5;
$h{val1}{unit11}{2}{ppp} = 105;

# j'ai plusieurs critères de tri, et je 'raccroche' le tri que je
voudrais effectuer à partir de $k3 car les boucles concernant $k et
$k2 servent dans une boucle principale.
foreach $k (keys %{$h}) { #ici val1
foreach $k2 (keys %{$h->{$k}}) { #ici unit11
# ici le tri que je voudrais effectuer -> unit11 classé selon 'rat'
# la méthode que vous m'avez indiquée fait effectivement le
classement que je souhaite, mais sur la totalité des valeurs suivant
les clés rattachées à unit11
foreach my $k3 ( sort
{ $h->{$k}->{$k2}->{$a->[0]}->{$a->[1]} <=>
$h->{$k}->{$k2}->{$b->[0]}->{$b->[1]} }
map { $t = $_; (map{[$t, $_]} keys
%{$h->{$k}->{$k2}->{$t}}) }
keys %{$h->{$k}->{$k2}}) {
print "$k3->[0] $k3->[1]
".$h->{$k}->{$k2}->{$k3->[0]}->{$k3->[1]}."n";
}
}
}

Ce que je voudrais, c'est en fait à partir de $k3, indiquer que c'est
'rat' qui détermine le trie, or, en passant par keys(), je ne vois pas
comment obtenir uniquement la valeur de 'rat' comme critère.


En fait ce que vous voulez trier ce sont les clés de la table de
hachage %{$h->{$k}{$k2}} ($k et $k2 sont donc constants pour le
tri). Et pour une clé donnée ($a par exemple), la valeur à comparer
(je suppose une comparaison numérique) est $h->{$k}{$k2}{$a}{rat}.
Donc :

foreach my $k (keys %{$h}) { #ici val1
foreach my $k2 (keys %{$h->{$k}}) { #ici unit11
foreach my $k3 (sort {
$h->{$k}{$k2}{$a}{rat} <=> $h->{$k}{$k2}{$a}{rat}
} keys %{$h->{$k}{$k2}}) {
# ici, les valeurs de $k3 arrivent triées...
print "$k $k2 $k3:n";
foreach my $f (qw/rat ooo iii ppp/) {
print "t$f -> $h->{$k}{$k2}{$k3}{$f}n"
}
}
}
}


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

Avatar
Paul Gaborit
À (at) Mon, 06 Feb 2006 13:38:15 +0100,
Paul Gaborit écrivait (wrote):
[...]
foreach my $k3 (sort {
$h->{$k}{$k2}{$a}{rat} <=> $h->{$k}{$k2}{$a}{rat}
} keys %{$h->{$k}{$k2}}) {


Il fallait lire (et écrire) :
foreach my $k3 (sort {
$h->{$k}{$k2}{$a}{rat} <=> $h->{$k}{$k2}{$b}{rat}
} keys %{$h->{$k}{$k2}}) {

($a et $b sont les deux valeurs à comparer...)

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

Avatar
ctobini
Bonjour et désolé pour la réponse tardive,

C'est parfait, j'ai pu trier ce que je voulais, comme je l'imaginais
:-)

Merci encore et bonne journée.

C. Tobini