PERL : push dans un tableau ou hash

Résolu/Fermé
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 - 21 oct. 2008 à 16:41
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 - 22 oct. 2008 à 14:58
Bonjour,

Je ne comprend pas pourquoi le code ci-après me renvois des doubles dans le tableau malgrés la commande exists ...


#!/usr/bin/env perl
my $raison="";
my %tableau;

for(my $cpt=0; $cpt <= 5; $cpt++){
	$token = "token ".$cpt;
	if ($cpt == 2) { $token = "token 1"; }
	print "compteur : $cpt\n";
	print "mot : $token\n";
	print "hash avant : \n\t@tableau";
	push @tableau, $token unless exists $tableau{$token};
	print "\n";
	print "hash apres : \n\t@tableau";
	print "\n\n";
}



Résultat :


compteur : 0
mot : token 0
hash avant : 
	
hash apres : 
	token 0

compteur : 1
mot : token 1
hash avant : 
	token 0
hash apres : 
	token 0 token 1

compteur : 2
mot : token 1
hash avant : 
	token 0 token 1
hash apres : 
	token 0 token 1 token 1

compteur : 3
mot : token 3
hash avant : 
	token 0 token 1 token 1
hash apres : 
	token 0 token 1 token 1 token 3

compteur : 4
mot : token 4
hash avant : 
	token 0 token 1 token 1 token 3
hash apres : 
	token 0 token 1 token 1 token 3 token 4

compteur : 5
mot : token 5
hash avant : 
	token 0 token 1 token 1 token 3 token 4
hash apres : 
	token 0 token 1 token 1 token 3 token 4 token 5
A voir également:

7 réponses

lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
21 oct. 2008 à 18:51
Re,

Alors tu fait comme ça
lami20j@debian:~/trash$ cat sbouli.pl
#!/usr/bin/env perl
my $raison="";
my %tableau;

for(my $cpt=0; $cpt <= 5; $cpt++){
        $token = "token ".$cpt;
        if ($cpt == 2) { $token = "token 1"; }
        print "compteur : $cpt\n";
        print "mot : $token\n";
        print "hash avant : \n\t@tableau";
        push @tableau, $token unless grep { /$token/ } @tableau;
        print "\n";
        print "hash apres : \n\t@tableau";
        print "\n\n";
}
lami20j@debian:~/trash$ perl sbouli.pl
compteur : 0
mot : token 0
hash avant :

hash apres :
        token 0

compteur : 1
mot : token 1
hash avant :
        token 0
hash apres :
        token 0 token 1

compteur : 2
mot : token 1
hash avant :
        token 0 token 1
hash apres :
        token 0 token 1

compteur : 3
mot : token 3
hash avant :
        token 0 token 1
hash apres :
        token 0 token 1 token 3

compteur : 4
mot : token 4
hash avant :
        token 0 token 1 token 3
hash apres :
        token 0 token 1 token 3 token 4

compteur : 5
mot : token 5
hash avant :
        token 0 token 1 token 3 token 4
hash apres :
        token 0 token 1 token 3 token 4 token 5
je te rappelle que tu dois tester les éléments du tableau et pas celle d'un hash qui n'existe pas
pour te convaincre tu peux ajouter à la fin, après la boucle
print scalar keys %tableau, "\n"; et tu verras le résultat

La fonction grep permet de vérifier si le tableau contient déjà un token

0
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 2
21 oct. 2008 à 19:06
super mais donc ... j'ai rien compris à la fonction exists .. je pensais que ça vérifiais l'existance de l'entrée dans le tableau (avec des [ ou le hash avec { )

stéphane
-1
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567 > sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014
21 oct. 2008 à 19:20
Pour un hash la fonction exists vérifié si la clé existe mais dans ton cas il n'y a pas de sens vu que tu dois vérifier plutôt les éléments du tableau.

En revanche comme je te l'ai dit, ton hash ne contient rien. Donc exists ne trouve aucune clé. Son comportement est normal ;-)
Mais si tu insistes et pour voir que exists fonctionne comme tu le penses il y a un moyen ;-) (En fait il y a toujours un moyen, mais tu me demandes trop de réfléchir ;-DDDD
#!/usr/bin/env perl
my $raison="";
my %tableau;

for(my $cpt=0; $cpt <= 5; $cpt++){
        $token = "token ".$cpt;
        if ($cpt == 2) { $token = "token 1"; }
        print "compteur : $cpt\n";
        print "mot : $token\n";
        print "hash avant : \n\t@tableau";
        push @tableau, $token unless exists $tableau{$token};
        $tableau{$token}=();
        print "\n";
        print "hash apres : \n\t@tableau";
        print "\n\n";
}
print scalar keys %tableau, "\n";

En fait j'ajoute d'abord le token et ensuite je remplis le hachage avec le token.
Donc maintenant exists trouvera une par une les clés et s'il la trouve il ne va pas la remettre dans le tableau vu qu'il existe déjà.
Tu vois à la fin qu'il y a 5 clé (ce sont les tokens)
-1
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
21 oct. 2008 à 17:48
Salut,

C'est à cause de if ($cpt == 2) { $token = "token 1"; }
Quand tu as "token 2" pour l'affichage il sera remplacer par "token 1".

@tableau n'est pas un hash.

En fait @ tableau contiens une liste
%tableau contiens aussi une liste, mais les éléments sont par paire.
Si tu affecte %tableau à @tableau tu ne fait que mettre une liste à plat, mais le hash est perdu.

lami20j@debian:~/trash$ cat sbouli.pl
#!/usr/bin/perl
use strict;use warnings;

my $raison="";
my %tableau;
my @tableau;

for(my $cpt=0; $cpt <= 5; $cpt++){
        my $token = "token ".$cpt;
#if ($cpt == 2) { $token = "token 1"; }
        print "compteur : $cpt\n";
        print "mot : $token\n";
        print "hash avant : \n\t@tableau";
        push @tableau,$token unless exists  $tableau{$token};
        print "\n";
        print "hash apres : \n\t@tableau";
        print "\n\n";
}
__END__
lami20j@debian:~/trash$ perl sbouli.pl
compteur : 0
mot : token 0
hash avant :

hash apres :
        token 0

compteur : 1
mot : token 1
hash avant :
        token 0
hash apres :
        token 0 token 1

compteur : 2
mot : token 2
hash avant :
        token 0 token 1
hash apres :
        token 0 token 1 token 2

compteur : 3
mot : token 3
hash avant :
        token 0 token 1 token 2
hash apres :
        token 0 token 1 token 2 token 3

compteur : 4
mot : token 4
hash avant :
        token 0 token 1 token 2 token 3
hash apres :
        token 0 token 1 token 2 token 3 token 4

compteur : 5
mot : token 5
hash avant :
        token 0 token 1 token 2 token 3 token 4
hash apres :
        token 0 token 1 token 2 token 3 token 4 token 5

P.S. Tu n'a rien à me dire?!
-1
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 2
21 oct. 2008 à 17:59
Hello cher lami20j :)


En fait ceci fait suite à nos mails ... tu n'as pas dû lire le dernier ...

Sinon pour :
"C'est à cause de if ($cpt == 2) { $token = "token 1"; }
Quand tu as "token 2" pour l'affichage il sera remplacer par "token 1". "

C'est voulu, j'essais de contruire un hash (ou un tableau dans le cas présent c'est pas dérangeant) avec les valeures :

token 1
token 1
token 3
token 4
token 5

je devrais avoir pour résultat :
token 1
token 3
token 4
token 5

mais pas 2 fois token 1 ... ya un unless exists

J'ai pas testé le code du post ... je vois ça dans la soirée ...

A +

Stéphane
-1
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
21 oct. 2008 à 18:11
Re,

alors fait comme ça
lami20j@debian:~/trash$ cat sbouli.pl
#!/usr/bin/perl
use strict;use warnings;

my $raison="";
my %tableau;
my @tableau;

for(my $cpt=0; $cpt <= 5; $cpt++){
        my $token = "token ".$cpt;
        if ($cpt == 2) { $token = "token 1"; }
        print "compteur : $cpt\n";
        print "mot : $token\n";
        print "hash avant : \n\t@tableau";
        unless (exists  $tableau{$token}) {
          push @tableau,$token if $cpt!=2;
        }
        print "\n";
        print "hash apres : \n\t@tableau";
        print "\n\n";
}
__END__
lami20j@debian:~/trash$ perl sbouli.pl
compteur : 0
mot : token 0
hash avant :

hash apres :
        token 0

compteur : 1
mot : token 1
hash avant :
        token 0
hash apres :
        token 0 token 1

compteur : 2
mot : token 1
hash avant :
        token 0 token 1
hash apres :
        token 0 token 1

compteur : 3
mot : token 3
hash avant :
        token 0 token 1
hash apres :
        token 0 token 1 token 3

compteur : 4
mot : token 4
hash avant :
        token 0 token 1 token 3
hash apres :
        token 0 token 1 token 3 token 4

compteur : 5
mot : token 5
hash avant :
        token 0 token 1 token 3 token 4
hash apres :
        token 0 token 1 token 3 token 4 token 5
mais c'est inutile puisque le même résultat tu l'obtiens avec
#!/usr/bin/perl
use strict;use warnings;

my @tableau;

for(my $cpt=0; $cpt <= 5; $cpt++){
        my $token = "token ".$cpt;
        if ($cpt == 2) { $token = "token 1"; }
        print "compteur : $cpt\n";
        print "mot : $token\n";
        print "hash avant : \n\t@tableau";
        push @tableau,$token if $cpt!=2;
        print "\n";
        print "hash apres : \n\t@tableau";
        print "\n\n";
}
__END__


-1
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 2
21 oct. 2008 à 18:38
hahahahaha

bon, ceci est un exemple conçu pour montrer mon problème de exists,

J'ai donc fait une boucle de 1 à 5 et pour le 2 (j'aurais pu choisir le 3), je remet le même token que pour le 1

donc le code :

unless (exists  $tableau{$token}) {
          push @tableau,$token if $cpt!=2;
        }


ne sert à rien, pour quoi le "token 1" est-il ajouté à l'itération numéro 2 alors que "token 1" est DEJA présent dans le tableau ??

Je veux que seuls les nouveaux token soit inséré dans le tableau

itération 1 : Je passe sur "token 1" le tableau est vide, je lui ajoute "token 1"
itération 2 : Je passe sur "token 1" (forcé par le if) le tableau contient deja "token 1" donc je ne lui ajoute pas
itération 3 : je passe sur "token 3" le tableau ne contient pas encore "token 3" je l'ajoute
etc ...
-1
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 2
21 oct. 2008 à 20:44
ok, je suis pas sûr de moi donc je poursuis, imaginons que je travail sur un hash désormais et pas sur un tableau. L'ensemble clef valeur sous la forme :

(
clef token 1 valeur 2,
clef token 3 valeur 1,
clef token 4 valeur 1,
clef token 5 valeur 1
)


j'imagine un truc dans ce gout là ...
#!/usr/bin/env perl
my $raison="";
my %monhash;

for(my $cpt=0; $cpt <= 5; $cpt++){
	$token = "token ".$cpt;
	if ($cpt == 2) { $token = "token 1"; }
	print "compteur : $cpt\n";
	print "mot : $token\n";
	print "hash avant : \n\t";
	print %monhash;
if (exists $monhash{$token})  {
    $monhash{$token}++;
} else {
    push %monhash, $token
}
	print "\n";
	print "hash apres : \n\t";
	print %monhash;
	print "\n\n";
}
-1
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 2
21 oct. 2008 à 20:50
ben tout betement ça doit être :

if (exists $tableau{$token})  {
    $tableau{$token}++;
} else {
    $tableau{$token}=1;
}
-1

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
21 oct. 2008 à 20:50
Re,

On ne peux pas faire push sur un hash
En revanche tu peux avoir un hash de tableau qui veut dire que pour chaque clé la valeur est un tableau anonyme
Par exemple
push @{$hash{$token}},$token
-1
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 2
21 oct. 2008 à 20:51
yes,

Je pense avoir compris mon erreur

pour moi un hash c'est %monhash

alors qu'en c'est : monhash

on intervient sur les éléments avec $monhash{$clef} un peu comme un tableau $montableau[$position]

merci en tout cas ... je poursuis demain

Stéphane
-1
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
21 oct. 2008 à 20:55
Re,

Pour avoir une image d'un hash de tableau
%hash = {
          cle1 => [ "val1", "val2"],
          cle2 => [ "a"   , "b"   ],
};

-1
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 2
22 oct. 2008 à 12:48
Si j'ai bien compris, on ne peut pas mettre un tableau dans un hash mais une référence à ce tableau,
moi je voudrais un hash internautes avec comme clef une adresse email et comme value un tableau :

%internautes :
email ---> email, id, nb, date1, date2, date3

exemple:

email_1@toto.com
email_1@toto.com, 1, 1, 20081022 12:30:00, 20081020 10:10:00, 'null'
email_2@toto.com
email_2@toto.com, 10, 2, 20081022 12:31:00, 20081019 20:15:05, 'null'
etc ....

mais ce bout de code ne me donne que le pointeur du tableau pas le tableau ....donc je n'ai tout le temps qu'un seul tableau modifié à chaque tour ....


#!/usr/bin/env perl
use Data::Dumper;

my %internautes;
my @temp_internaute;
my $addr;

for(my $i=1; $i<10; $i++) {
	
	$addr="email_".$i."@toto.com";
	$addr="email_".$i."@toto.com";
	
	if ( exists $internautes{$addr} ) {
			@temp_internaute=$internautes{$addr};
			$temp_internaute[2]++;
			$internautes{$addr}=\@temp_internaute;
	} else {
			@temp_internaute=($addr,15,1,'20081022 12:35:00', '20081020 12:30:00', 'null');
			$internautes{$addr}=\@temp_internaute;
	}
}
print Dumper %internautes;
__END__

-1
sbouli Messages postés 200 Date d'inscription jeudi 20 décembre 2007 Statut Membre Dernière intervention 14 août 2014 2
22 oct. 2008 à 14:58
J'ai réussi en faisant :

if ( exists $internautes{$addr} ) {
            $internautes{$addr}[2]++;
} else {
            @$temp_internaute=($addr,$raisons{$raison},1,&datetime, "$revMsgDateStr $msgHr:$msgMin:00", 'null');
            $internautes{$clef}=$temp_internaute;
            undef $temp_internaute;}
-1