=encoding iso-8859-1 =head1 NAME/NOM perllol - Manipulation des tableaux de tableaux en Perl =head1 DESCRIPTION =head2 Déclaration et accès aux tableaux de tableaux La chose la plus simple à construire est un tableau de tableaux (parfois appelé de façon peu précise une liste de listes). C'est raisonnablement facile à comprendre et presque tout ce qui s'y applique pourra aussi être appliqué par la suite aux structures de données plus fantaisistes. Un tableau de tableau est juste un bon vieux tableau @TdT auquel vous pouvez accéder avec deux indices, comme C<$TdT[3][2]>. Voici une déclaration du S # affecte à notre tableau un tableau de références à des tableaux @TdT = ( [ "fred", "barney" ], [ "george", "jane", "elroy" ], [ "homer", "marge", "bart" ], ); print $TdT[2][2]; bart Maintenant, vous devez faire bien attention au fait que les parenthèses extérieures sont bien des parenthèses et pas des accolades ou des crochets. C'est parce que vous affectez dans un @tableau. Vous avez donc besoin de parenthèses. Si vous Iaviez I voulu que cela soit un @TdT, mais plutôt une référence à lui, vous auriez pu faire quelque chose du style de S # affecte une référence à une liste de références de liste $ref_to_TdT = [ [ "fred", "barney", "pebbles", "bambam", "dino", ], [ "homer", "bart", "marge", "maggie", ], [ "george", "jane", "elroy", "judy", ], ]; print $ref_to_TdT->[2][2]; Notez que le type des parenthèses extérieures a changé et donc notre syntaxe d'accès aussi. C'est parce que, contrairement au C, en Perl vous ne pouvez pas librement échanger les tableaux et leurs références. C<$ref_to_TdT> est une référence à un tableau, tandis que C<@TdT> est un tableau proprement dit. De la même manière, C<$TdT[2]> n'est pas un tableau, mais une référence à un tableau. Ainsi donc vous pouvez écrire S $TdT[2][2] $ref_to_TdT->[2][2] au lieu de devoir écrire ceci : $TdT[2]->[2] $ref_to_TdT->[2]->[2] Vous pouvez le faire car la règle dit que, entre des crochets ou des accolades adjacents, vous êtes libre d'omettre la flèche de déréférencement. Mais vous ne pouvez pas faire cela pour la toute première flèche si c'est un scalaire contenant une référence, ce qui signifie que $ref_to_TdT en a toujours besoin. =head2 Développer la vôtre Tout ceci est bel et bien pour la déclaration d'une structure de données fixe, mais si vous voulez ajouter de nouveaux éléments à la volée, ou tout contruire à partir de S Tout d'abord, étudions sa lecture à partir d'un fichier. C'est quelque chose comme ajouter une rangée à la fois. Nous présumerons qu'il existe un fichier tout simple dans lequel chaque ligne est une rangée et chaque mot un élément. Voici la bonne façon de le faire si vous essayez de développer un tableau @TdT les contenant S while (<>) { @tmp = split; push @TdT, [ @tmp ]; } Vous auriez aussi pu charger tout cela dans une S for $i ( 1 .. 10 ) { $TdT[$i] = [ somefunc($i) ]; } Ou vous auriez pu avoir une variable temporaire traînant dans le coin et contenant le tableau. for $i ( 1 .. 10 ) { @tmp = somefunc($i); $TdT[$i] = [ @tmp ]; } Il est très important que vous vous assuriez d'utiliser le constructeur de référence de tableau C<[]>. C'est parce que ceci serait très S $TdT[$i] = @tmp; Voyez vous, affecter comme ceci un tableau nommé à un scalaire ne fait que compter le nombre d'éléments dans @tmp, ce qui n'est probablement pas ce que vous désirez. Si vous utilisez C, vous devrez ajouter quelques déclarations pour que tout S use strict; my(@TdT, @tmp); while (<>) { @tmp = split; push @TdT, [ @tmp ]; } Bien sûr, vous n'avez pas du tout besoin de donner un nom au tableau S while (<>) { push @TdT, [ split ]; } Vous n'êtes pas non plus obligé d'utiliser push(). Vous pourriez juste faire une affectation directe si vous savez où vous voulez le S my (@TdT, $i, $line); for $i ( 0 .. 10 ) { $line = <>; $TdT[$i] = [ split ' ', $line ]; } ou même S my (@TdT, $i); for $i ( 0 .. 10 ) { $TdT[$i] = [ split ' ', <> ]; } Vous devriez en général lorgner d'un regard mauvais l'usage de fonctions qui peuvent potentiellement retourner des listes dans un contexte scalaire sans le formuler explicitement. Ceci sera plus clair pour le lecteur de S my (@TdT, $i); for $i ( 0 .. 10 ) { $TdT[$i] = [ split ' ', scalar(<>) ]; } Si vous voulez utiliser une variable $ref_to_TdT comme référence à un tableau, vous devez faire quelque chose comme S while (<>) { push @$ref_to_TdT, [ split ]; } Maintenant vous pouvez ajouter de nouvelles rangées. Et pour ajouter de nouvelles S Si vous traitez juste des matrices, le plus facile est souvent d'utiliser une simple S for $x (1 .. 10) { for $y (1 .. 10) { $TdT[$x][$y] = func($x, $y); } } for $x ( 3, 7, 9 ) { $TdT[$x][20] += func2($x); } Peu importe que ces éléments soient déjà là ou S ils seront créés joyeusement pour vous et, si besoin, les éléments intermédiaires seront initialisés à C. Si vous voulez juste en ajouter à une rangée, vous devrez faire quelque chose ayant l'air un peu plus S # ajoute de nouvelles colonnes à une rangée existante push @{ $TdT[0] }, "wilma", "betty"; Remarquez qu'on I juste S push $TdT[0], "wilma", "betty"; # FAUX ! En fait, cela ne se compilerait même pas. Pourquoi S Parce que l'argument de push() doit être un véritable tableau, et non pas une simple référence. =head2 Accès et sortie Maintenant il est temps de sortir votre structure de données. Comment allez-vous faire une telle S Eh bien, si vous voulez uniquement l'un des éléments, c'est S print $TdT[0][0]; Si vous voulez sortir toute la chose, toutefois, vous ne pouvez pas S print @TdT; # FAUX car vous obtiendrez juste la liste des références et perl ne déréférencera jamais automatiquement les choses pour vous. Au lieu de cela, vous devez faire tourner une boucle ou deux. Ceci imprime toute la structure, en utilisant la construction for() dans le style du shell pour boucler d'un bout à l'autre de l'ensemble des indices extérieurs. for $aref ( @TdT ) { print "\t [ @$aref ],\n"; } Si vous voulez garder la trace des indices, vous pouvez faire S for $i ( 0 .. $#TdT ) { print "\t elt $i is [ @{$TdT[$i]} ],\n"; } ou peut-être même ceci. Remarquez la boucle intérieure. for $i ( 0 .. $#TdT ) { for $j ( 0 .. $#{$TdT[$i]} ) { print "elt $i $j is $TdT[$i][$j]\n"; } } Comme vous pouvez le voir, cela devient un peu compliqué. C'est pourquoi il est parfois plus facile de prendre une variable temporaire en S for $i ( 0 .. $#TdT ) { $aref = $TdT[$i]; for $j ( 0 .. $#{$aref} ) { print "elt $i $j is $TdT[$i][$j]\n"; } } Hmm... c'est encore un peu laid. Pourquoi pas S for $i ( 0 .. $#TdT ) { $aref = $TdT[$i]; $n = @$aref - 1; for $j ( 0 .. $n ) { print "elt $i $j is $TdT[$i][$j]\n"; } } =head2 Tranches Si vous voulez accèder à une tranche (une partie d'une rangée) d'un tableau multidimensionnel, vous allez devoir faire un peu d'indiçage fantaisiste. Car, tandis que nous avons un joli synonyme pour les éléments seuls via la flèche de pointeur pour le déréférencement, il n'existe pas de telle commodité pour les tranches (souvenez-vous, bien sûr, que vous pouvez toujours écrire une boucle pour effectuer une opération sur une tranche). Voici comment faire une opération en utilisant une boucle. Nous supposerons avoir une variable @TdT comme précédemment. @part = (); $x = 4; for ($y = 7; $y < 13; $y++) { push @part, $TdT[$x][$y]; } Cette même boucle peut être remplacée par une opération de S @part = @{ $TdT[4] } [ 7..12 ]; mais comme vous pouvez l'imaginer, c'est plutôt rude pour le lecteur. Et si vous vouliez une I, telle que $x varie dans 4..8 et $y dans 7 à S<12 ?> Hmm... voici la façon S @newTdT = (); for ($startx = $x = 4; $x <= 8; $x++) { for ($starty = $y = 7; $y <= 12; $y++) { $newTdT[$x - $startx][$y - $starty] = $TdT[$x][$y]; } } Nous pouvons réduire une partie du bouclage via des tranches. for ($x = 4; $x <= 8; $x++) { push @newTdT, [ @{ $LoL[$x] } [ 7..12 ] ]; } Si vous faisiez des transformations schwartziennes, vous auriez probablement choisi map pour S @newTdT = map { [ @{ $TdT[$_] } [ 7..12 ] ] } 4 .. 8; Bien sûr, si votre directeur vous accuse de rechercher la sécurité de l'emploi (ou l'insécurité rapide) à l'aide d'un code indéchiffrable, il sera difficile d'argumenter. :-) Si j'étais vous, je mettrais cela dans une S @newTdT = splice_2D( \@LoL, 4 => 8, 7 => 12 ); sub splice_2D { my $lrr = shift; # réf à un tableau de réfs. de tableau ! my ($x_lo, $x_hi, $y_lo, $y_hi) = @_; return map { [ @{ $lrr->[$_] } [ $y_lo .. $y_hi ] ] } $x_lo .. $x_hi; } =head1 VOIR AUSSI L, L, L. =head1 AUTEUR Tom Christiansen > Dernière mise à jour : Thu Jun 4 16:16:23 MDT 1998 =head1 TRADUCTION =head2 Version Cette traduction française correspond à la version anglaise distribuée avec perl 5.10.0. Pour en savoir plus concernant ces traductions, consultez L. =head2 Traducteur Roland Trique >. =head2 Relecture Régis Julié >. Paul Gaborit (Paul.Gaborit at enstimac.fr).