OVH Cloud OVH Cloud

remplissage d'un hash problèmatique sur 2 filehandles

5 réponses
Avatar
ctobini
Bonjour,

J'ai une grosse gal=E8re :

Je suis en train de rassembler les infos de 2 fichiers, le second
permettant de mettre =E0 jour un champ du premier.

Je stocke les infos dans un hash comme dans l'exemple :

my %h;

open FICHIER1
tant que FICHIER1
si pattern trouve
regex: stocker variables $champ1 et $champ2
$h{$champ1}{$champ2}{donnee} =3D 'standard'
close FICHIER1

open FICHIER2
tant que FICHIER2
si pattern trouve
regex: stocker variables $champ1 et $champ2
si exists $h{$champ1}{$champ2}
$h{$champ1}{$champ2}{donnee} =3D 'pas_standard'
close FICHIER2

A la sortie de FICHIER1 j'ai un %h bien constitu=E9, tout beau.

Apr=E8s le FICHIER2, j'ai un %h rempli avec toutes les lignes, malgr=E9
le 'si exists'. Je pr=E9cise que j'ai mis un print dans le 'si exists'
et qu'il n'y a aucune ligne qui match, rien ne devrait se produire donc
=E0 la sortie de FICHIER2 =E0 ce stade du script.

Verriez-vous une raison pour laquelle le %h serait nourri ?

En vous remerciant,

C=2E Tobini

5 réponses

Avatar
Nicolas George
"ctobini" wrote in message
:
open FICHIER2
tant que FICHIER2
si pattern trouve
regex: stocker variables $champ1 et $champ2
si exists $h{$champ1}{$champ2}
$h{$champ1}{$champ2}{donnee} = 'pas_standard'
close FICHIER2


Ce n'est pas du perl, ça. Montre-nous du perl.

Avatar
Paul Gaborit
À (at) 22 Nov 2006 08:34:52 -0800,
"ctobini" écrivait (wrote):
Je suis en train de rassembler les infos de 2 fichiers, le second
permettant de mettre à jour un champ du premier.

Je stocke les infos dans un hash comme dans l'exemple :

my %h;

open FICHIER1
tant que FICHIER1
si pattern trouve
regex: stocker variables $champ1 et $champ2
$h{$champ1}{$champ2}{donnee} = 'standard'
close FICHIER1

open FICHIER2
tant que FICHIER2
si pattern trouve
regex: stocker variables $champ1 et $champ2
si exists $h{$champ1}{$champ2}
$h{$champ1}{$champ2}{donnee} = 'pas_standard'
close FICHIER2

A la sortie de FICHIER1 j'ai un %h bien constitué, tout beau.

Après le FICHIER2, j'ai un %h rempli avec toutes les lignes, malgré
le 'si exists'. Je précise que j'ai mis un print dans le 'si exists'
et qu'il n'y a aucune ligne qui match, rien ne devrait se produire donc
à la sortie de FICHIER2 à ce stade du script.

Verriez-vous une raison pour laquelle le %h serait nourri ?


Oui : l'autovivification !

Ce gros mot pour dire que Perl crée les clés inexistantes au fur et à
mesure qu'il en a besoin.

Votre test devrait être écrit de la manière suivante :

if (exists $h{$champ1} and exists $h{$champ1}{$champ2}) {
...
}

Lorsqu'on teste "exists $h{$champ1}{$champ2}", on teste l'existence de
la clé '$champ2'. Perl crée donc (autovivifie) la clé '$champ1'.


PS: l'écriture en pseudo-code n'est pas toujours très compréhensible.
De plus, il arrive que l'erreur si situe dans le code qu'on croit
pouvoir ne pas montrer...

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

Avatar
ctobini
Bonjour et merci de vos réponses,

Ca fonctionne effectivement avec exists $h{$champ1} &&
$h{$champ1}{$champ2}, merci beaucoup !

Ce qui m'étonne c'est que si exists $h{$champ1}{$champ2} :

if(exists $h{$champ1}{$champ2}) {
print
}

devrait imprimer puisque $champ2 existe. $champ2 est un nombre de 1 à
5 redondant, sur 15 millions de lignes la ligne aurait dû être
imprimée un certain nombre de fois (et même un nombre certain).

Pour le pseudo-code désolé, j'écrirai en code tout court désormais
:-)

C. Tobini


À (at) 22 Nov 2006 08:34:52 -0800,
"ctobini" écrivait (wrote):
Je suis en train de rassembler les infos de 2 fichiers, le second
permettant de mettre à jour un champ du premier.

Je stocke les infos dans un hash comme dans l'exemple :

my %h;

open FICHIER1
tant que FICHIER1
si pattern trouve
regex: stocker variables $champ1 et $champ2
$h{$champ1}{$champ2}{donnee} = 'standard'
close FICHIER1

open FICHIER2
tant que FICHIER2
si pattern trouve
regex: stocker variables $champ1 et $champ2
si exists $h{$champ1}{$champ2}
$h{$champ1}{$champ2}{donnee} = 'pas_standard'
close FICHIER2

A la sortie de FICHIER1 j'ai un %h bien constitué, tout beau.

Après le FICHIER2, j'ai un %h rempli avec toutes les lignes, malgré
le 'si exists'. Je précise que j'ai mis un print dans le 'si exists'
et qu'il n'y a aucune ligne qui match, rien ne devrait se produire donc
à la sortie de FICHIER2 à ce stade du script.

Verriez-vous une raison pour laquelle le %h serait nourri ?


Oui : l'autovivification !

Ce gros mot pour dire que Perl crée les clés inexistantes au fur et à
mesure qu'il en a besoin.

Votre test devrait être écrit de la manière suivante :

if (exists $h{$champ1} and exists $h{$champ1}{$champ2}) {
...
}

Lorsqu'on teste "exists $h{$champ1}{$champ2}", on teste l'existence de
la clé '$champ2'. Perl crée donc (autovivifie) la clé '$champ1'.


PS: l'écriture en pseudo-code n'est pas toujours très compréhensibl e.
De plus, il arrive que l'erreur si situe dans le code qu'on croit
pouvoir ne pas montrer...

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



Avatar
Paul Gaborit
À (at) 23 Nov 2006 06:51:14 -0800,
"ctobini" écrivait (wrote):
Ca fonctionne effectivement avec exists $h{$champ1} &&
$h{$champ1}{$champ2}, merci beaucoup !


...avec :

exists $h{$champ1} and exists $h{$champ1}{$champ2}
~~~~~~

De plus, il vaut mieux utiliser 'and' plutôt que '&&' : c'est plus
lisible et le niveau de priorité est souvent meilleur pour la
compréhension.

Ce qui m'étonne c'est que si exists $h{$champ1}{$champ2} :

if(exists $h{$champ1}{$champ2}) {
print
}

devrait imprimer puisque $champ2 existe. $champ2 est un nombre de 1 à
5 redondant, sur 15 millions de lignes la ligne aurait dû être
imprimée un certain nombre de fois (et même un nombre certain).


Le test 'exists $h{$champ1}{$champ2}' regarde si la clé $champ2 existe
*dans* la table de hachage anonyme référencée par '$h{$champ1}' (c'est
cette table et sa référence qui sont autovivifiées si elles
n'existaient pas).

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

Avatar
ctobini
Merci beaucoup pour les explications, c'est compris.

Bon week-end,

C. Tobini



À (at) 23 Nov 2006 06:51:14 -0800,
"ctobini" écrivait (wrote):
Ca fonctionne effectivement avec exists $h{$champ1} &&
$h{$champ1}{$champ2}, merci beaucoup !


...avec :

exists $h{$champ1} and exists $h{$champ1}{$champ2}
~~~~~~

De plus, il vaut mieux utiliser 'and' plutôt que '&&' : c'est plus
lisible et le niveau de priorité est souvent meilleur pour la
compréhension.

Ce qui m'étonne c'est que si exists $h{$champ1}{$champ2} :

if(exists $h{$champ1}{$champ2}) {
print
}

devrait imprimer puisque $champ2 existe. $champ2 est un nombre de 1 à
5 redondant, sur 15 millions de lignes la ligne aurait dû être
imprimée un certain nombre de fois (et même un nombre certain).


Le test 'exists $h{$champ1}{$champ2}' regarde si la clé $champ2 existe
*dans* la table de hachage anonyme référencée par '$h{$champ1}' (c' est
cette table et sa référence qui sont autovivifiées si elles
n'existaient pas).

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