Insérer tableau dans tableau associatif

Fermé
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 - Modifié par blux le 2/01/2015 à 18:02
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 - 8 janv. 2015 à 17:04
Bonjour,

je cherche à insérer un tableau (normal) dans une cellule d'un tableau associatif afin de pouvoir le parcourir plus tard.

Genre :

'boucle sur $i
$TAB{$i}{0} = "toto";
$TAB{$i}{1} = "1";
'boucle de remplissage de tableau
@TABLEAU[$j][0] = "titi"
@TABLEAU[$j][1] = "tata"
'fin boucle remplissage
$TAB{$i}{2} = @TABLEAU
fin boucle $i
....
'boucle sur $i
@TABLEAU = $TAB{$i}{2}
'boucle sur @TABLEAU
...
'fin boucle
'fin boucle

Mon problème est que scalar(@TABLEAU) est égal à 1 quand je veux le récupérér, donc j'ai un peu perdu des infos dans la manip...

Je dois faire une énorme bourde, mais je ne m'y connais pas assez en structures de données pour voir où...

Si quelqu'un peut m'éclairer, merci d'avance !

A+ blux
 "Les cons, ça ose tout.
C'est même à ça qu'on les reconnait"

2 réponses

[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
5 janv. 2015 à 17:38
Salut blux,

Il y a plusieurs problèmes.

Tu n'affectes pas correctement les valeurs du tableau.

C'est comme cela que l'on fait :

# déclaration
my @TABLEAU;

# affectation
$TABLEAU[0][0] = "titi";


Ensuite, pour intégrer ton tableau à ton hash, tu dois pouvoir faire :
$TAB{$i}{2} = \@TABLEAU;
si ce que tu veux c'est affecter une référence au tableau créé

La référence fonctionnera comme un "pointeur" dans d'autres langages : tu accèdes à la même structure de données en dé-référençant la référence.

Note que le nommage de "%TAB" pour un hash n'est pas forcément un choix très lisible.

Le code suivant illustre un exemple de mise en oeuvre :
#!/usr/bin/perl

use strict;
use warnings;

my %hash;
$hash{0}{0} = "toto";
$hash{0}{1} = "1";

my @arr;
$arr[0][0] = "titi";
$arr[0][1] = "tata";

# on assigne une référence au tableau
$hash{0}{2} = \@arr;

print "Affichage du contenu du tableau référencé :\n";
# afficher "titi"
print $hash{0}{2}[0][0] . "\n";
# afficher "tata"
print $hash{0}{2}[0][1] . "\n";

# modification d'un élément du tableau
print "modification d'un élément du tableau\n";
$arr[0][0] = "tutu";

print "Affichage après modification\n";
# l'affichage en passant par la référence affiche tutu
print $hash{0}{2}[0][0] . "\n";
# afficher "tata"
print $hash{0}{2}[0][1] . "\n";


cela donne :

Affichage du contenu du tableau référencé :
titi
tata
modification d'un élément du tableau
Affichage après modification
tutu
tata

mais cela a l'air très compliqué ta structure de données.


Dal
0
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 3 289
5 janv. 2015 à 18:15
J'ai du me tromper en écrivant le pseudo-code, je n'avais pas envie de faire d'en faire figurer l'intégralité ici ;-)
Mes noms de variables sont plutôt parlants habituellement !

Cette structure de données est juste pour simuler une relation 1-n telle qu'on la conçoit dans une base de données.

Pour récupérer le tableau inséré dans ma cellule, je suis obligé de passer par le tableau 'conteneur' via le paquet de 4 indices ou je peux l'extraire et le mettre ailleurs ?
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
5 janv. 2015 à 19:25
Je ne suis pas sûr de bien comprendre.

Mais si ce que tu demandes c'est : est-ce que je peux me servir de la référence stockée dans le hash d'une autre façon qu'à partir du hash, la réponse est oui.

Tu peux le faire à partir du tableau d'origine, comme montré par le code d'exemple, ou tu peux copier cette référence dans une autre variable et déréfécencer à partir de là.

Tu peux aussi créer directement un tableau dans ton hash, sans avoir à créer un tableau préexistant, y pousser les valeurs avec push, et récupérer une référence à ce tableau pour gérer ce contenu indépendamment du hash.


Dal
0
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 3 289
Modifié par blux le 6/01/2015 à 11:55
Je ne me suis pas fait suffisamment comprendre, je pense.
Ce que je veux, c'est mettre un tableau différent pour chaque 'ligne' de mon tableau hashé.

Lorsque je vais relire mon tableau hashé, je veux récupérer le tableau qui est rattaché à chaque 'ligne'. C'est plus clair ?

exemple :

un tableau de hash pour un matériel informatique avec toute une série d'infos uniques (type, date d'achat, ram, dd...) ET pour chaque matériel la liste de ses pannes, par exemple. Donc tableau des pannes inséré dans la cellule qui va bien du tableau de hash.

Quand je relis mon tableau de hash, je récupère mes infos 'matériel' et je veux aussi boucler sur toutes les pannes de chaque matériel.

Pour le reste de tes explications, je veux bien un 'tit exemple, si c'est pas abuser...

Tu peux le faire à partir du tableau d'origine, comme montré par le code d'exemple, ou tu peux copier cette référence dans une autre variable et déréfécencer à partir de là.

Tu peux aussi créer directement un tableau dans ton hash, sans avoir à créer un tableau préexistant, y pousser les valeurs avec push, et récupérer une référence à ce tableau pour gérer ce contenu indépendamment du hash.


Et comment puis-je faire pour parcourir le tableau que j'ai référencé ? Comment obtenir sa taille (fonction scalar ?)

print $hash{0}{2}[0][0] . "\n";


<edit>
bon, j'ai fini par trouver la bonne syntaxe !

Mais comme j'ai omis de dire que $arr est réinitialisé pour chaque ligne de $hash (je veux un tableau avec des valeurs différentes) seule la dernière 'version' de mon $arr est stockée dans toutes les lignes de $hash.

Je veux créer un tableau $arr différent pour chaque ligne de $hash et récupérer le $arr qui correspond à ce que j'ai mis lors du remplissage à mon parcours final de $hash

Et là, ça coince...
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
6 janv. 2015 à 11:14
ok, et tu stockes ta liste de matériels dans un array pour pouvoir énumérer le parc informatique?
0
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 3 289
6 janv. 2015 à 12:39
C'est exactement ça, sauf que ce n'est pas du tout pour gérer un parc informatique ;-)

C'est juste, comme je l'expliquais, pour simuler une relation 1-n de bases de données, si le concept t'est familier...
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié par [Dal] le 6/01/2015 à 12:54
Salut blux,

Avec tes indications plus concrètes de structure de données de matériels d'un parc informatique avec leurs pannes respectives, je comprends mieux qu'avec des toto et des titi :-)

essayes un truc comme cela :

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

# for storing all the park
my %park;

# for adding a new hardware
sub add_hardw {
    my ($serial_num, $name, $type, $date_bought, $ram, $hd) = @_;
    my @failures;

    # adding an entry to the hash using the serial number as the key, cloning the values
    $park{$serial_num} = {
        name => $name,
        type => $type,
        date_bought => $date_bought,
        ram => $ram,
        hd => $hd,
        failures => \@failures
    };
}

print "Création d'une nouvelle entrée pour un matériel\n";
add_hardw("123456", "PC12", "desktop", "2014-02-26", "4GB", "500GB");

print "ajout de quelques pannes\n";
push $park{"123456"}{failures}, "2015-01-05 - panne du ventilateur";
push $park{"123456"}{failures}, "2015-01-06 - câble ethernet sectionné";

print "affectation d'une référence de la liste des pannes d'un matériel à un scalaire \$temp\n";
my $temp = $park{"123456"}{failures};

print "changement du libellé de la première panne en passant par %park\n";
$park{"123456"}{failures}[0] = "2015-01-05 - panne du ventilateur (coincé par un stylo)";

print "changement du libellé de la seconde panne en passant par \$temp\n";
@$temp[1] = "2015-01-06 - câble ethernet sectionné (dévoré par un rongeur)";

print "Création d'une nouvelle entrée pour un autre matériel, avec ajout d'une panne\n";
add_hardw("123457", "Imprimante YH", "imprimante", "2014-05-02", "1GB", "150GB");
$temp = $park{"123457"}{failures};
push @$temp, "2015-01-06 - l'imprimante ne s'allume plus";
                                                                                                                                                                                                                   
print Dumper(%park);

En ligne 16, les accolades à la suite du signe égal dans la création de la nouvelle entrée de hash opèrent une copie des données contenues dans les variables utilisées (locales à la fonction dans ce code) qui sont mises dans le hash (qui est une variable globale, utilisable ailleurs dans le code).

Parmi les éléments clonés, en ligne 22,
failures => \@failures
clone une référence à un tableau.

Lorsqu'une autre entrée de hash est créée en ligne 43, c'est un nouveau hash qui est ajouté, avec des données indépendantes.

On crée donc un hash de hashs, chaque hash contenu incluant une référence à un tableau (pour stocker les anomalies séquentiellement).

Le code illustre comment tu peux accéder au tableau en passant par le hash, ou par une référence au tableau stocké dans une des entrées du hash, et comment déréférencer une référence d'un tableau stockée dans un scalaire ($temp est la référence et @$temp la déréférence comme un tableau).

Cela dit, je trouve personnellement la notation
$park{"123456"}{failures}[0]
suffisamment lisible, et je ne vois pas vraiment l'intérêt de passer par une variable temporaire pour la manipulation indirecte du tableau.

J'ai aussi pris le parti de ce que %park soit un hash dans cet exemple, dont la clef est un numéro unique identifiant le matériel.


Dal
0
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 3 289
Modifié par blux le 6/01/2015 à 13:46
Et comment fais-je pour savoir combien occurrences de failures pour un $park donné ?

Si tu veux vraiment avoir le vrai projet, je peux te le passer en MP...
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié par [Dal] le 6/01/2015 à 14:36
C'est confus car tu dis "$park".. park est un hash %park qui contient tous les matériels.

Si tu veux avoir la somme de toutes les anomalies pour le parc informatique tous matériels confondus, tu énumères les clefs du hash %park et tu cumules dans une boucle le nombre d'éléments de chaque array @failures contenu dans chaque hash accessible par chaque clef.

Par exemple :

my $total_failures = 0;
while ( my ($serial_num, $inner_hash) = each(%park) ) {
    $total_failures = $total_failures +
        scalar(@{$park{$serial_num}{failures}});
}
print "total_failures = $total_failures\n";


La ligne 4 ci-dessus, utilise le fait qu'en Perl, utiliser un array dans un contexte scalaire, permet d'obtenir le nombre d'éléments de l'array.

Si tu veux juste le nombre d'anomalies pour un matériel donné, tu accèdes directement au bon matériel, et tu n'as pas besoin de boucle : tu utilises juste la référence au array en tant que scalaire, en prenant soin de la déréférencer préalablement comme ci-dessus avec
@{ ... }
(pour que Perl sache que c'est un array).

my $failures_for_123456;
$failures_for_123456 = scalar(@{$park{"123456"}{failures}});


scalar()
est utilisé à des fins de lisibilité, sinon, il suffit de faire ceci pour utiliser l'array comme scalaire et obtenir le nombre de ses éléments :

$failures_for_123456 = @{$park{"123456"}{failures}};


Dal
0
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 3 289
6 janv. 2015 à 14:43
Ca s'éclaircit !
Je vais voir comment je peux tourner tout ça...
Merci.
0
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 3 289
6 janv. 2015 à 15:53
Ca coince, car je veux que failures ait deux champs...
Comment puis-je le déclarer et/ou le remplir lors du push $park ?
0
blux Messages postés 25991 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 22 avril 2024 3 289
6 janv. 2015 à 16:31
en plus, je n'arrive pas à faire l'insertion :

  push $TAB_GRP{$GRP}{TAILLE},$ANC_CLI ;


J'ai l'erreur :

Type of arg 1 to push must be array (not hash element) at cumul.pl line 32, near "$ANC_CLI ;"
0