Programmation Perl/Fonctions sur listes

Programmation Perl
Programmation Perl
Programmation Perl
Sommaire




Modifier ce modèle


Rappels sur les listes

modifier

Une liste est une suite de mots, de nombres… tout scalaire à vrai dire. Une liste stockée forme un tableau ou un tableau associatif (que nous verrons plus loin).

une liste

modifier

Pour créer une liste on utilise les parenthèses () de cette manière :

( "5.0", "truc" , 7, $autre_valeur )

Nous avons là une suite de scalaires : "5.0", "truc", 7 et la valeur stockée dans la variable scalaire $autre_valeur.

créer un tableau

modifier

Pour pouvoir la manipuler plus tard dans le programme, nous la stockons dans une variable. La variable est donc un tableau signalé par le sigil @.

Exemple avec parenthèses :

my @bon_a_manger = ( "poire", "chocolat", "sucre", "sirop", "bonbons", "fromage" );

Mais il y a d'autres opérateurs dédiés à la création de listes, comme qw qui crée une liste de mots (quoted words). Cet opérateur est préféré aux parenthèses dû à sa concision.

Exemple avec qw :

my @bon_a_manger = qw/poire chocolat sucre sirop bonbons fromage/;

La création de la liste est plus concise. Mais ceci va plus loin encore (voir la création de tableaux associatifs avec qw).

Créer un tableau associatif

modifier

Un tableau associatif (ou table de hachage) est une structure permettant d'associer à un scalaire un autre scalaire. C'est une liste un peu plus complexe qu'un tableau et le sigil est différent (%).

La création de ce type de liste se fait également avec des parenthèses, mais on ajoute également (facultatif) un opérateur => pour voir facilement la clé et sa valeur :

my %bon_a_manger = ( "fruit" => "cerise", "légume" => "patate" );

À savoir : l'opérateur => force l'interprétation de la variable à sa gauche comme une chaîne de caractères, donc les guillemets sont inutiles. Même exemple, mais avec qw :

my %bon_a_manger = qw/fruit cerise légume patate/;

Là encore nous voyons la concision apportée par cet opérateur. %bon_a_manger a le sigil % donc Perl sait qu'il doit ranger les mots par paires de la manière clé-valeur ("fruit" => "cerise", "légume" => "patate").

Fonctions de manipulation de listes

modifier

Il existe un nombre assez conséquent de fonctions de manipulation de listes (tableaux, tableaux associatifs). Nous allons aborder les plus courantes. Il n'est pas obligatoire de les connaître toutes par cœur.

.. : créer une suite d'éléments

modifier

On pourrait vouloir par exemple créer des suites longues d'éléments qui s'enchaînent. Par exemple, avec l'opérateur .. écrire une suite de 1 à 100 n'est pas plus compliqué que :

( 1 .. 100 ) # toutes les valeurs entières de 1 à 100

Nous pouvons faire également la même chose avec des lettres :

( 'a' .. 'z' ) # renvoie toutes les lettres de l'alphabet

exemple : les lettres de 'a' à 'zz'

modifier

Nous allons afficher à l'écran toutes les combinaisons des lettres de 'a' à 'zz' :

foreach my $var ( 'a' .. 'zz' )
{
	say $var; # affiche tour à tour chacune des valeurs de 'a' à 'zz'
}

join : concatène tous les éléments d'une liste

modifier

La commande join permet de concaténer tous les éléments d'une liste avec un motif (une chaîne de caractères par exemple) entre chaque élément.

Exemple : afficher tous les éléments d'un tableau séparés par un double point.

my @fruits = qw/ poire cerise pomme fraise /;
say join(' : ', @fruits);

Affichera : « poire : cerise : pomme : fraise ».

map : transforme tous les éléments d'une liste

modifier

Conseil : pour comprendre correctement cette fonction, voyez au moins le cours sur les fonctions et les procédures.

Cette fonction applique une transformation à tous les éléments d'un tableau ou d'une table de hachage. map prend en argument un bloc de code à exécuter et une liste (ou tableau). Il retourne une liste d'éléments modifiés.

Un exemple simple, on va doubler les valeurs d'un tableau :

my @simple = ( 1 .. 3 );
my @double = map { $_ * 2 } @simple; # on double toutes les valeurs
say foreach @double; # 246

Comme plus haut mais en une seule ligne :

say foreach map { $_ * 2 } ( 1 .. 3 ) ; # ce code est un peu plus dur à lire que les autres, n'hésitez pas à le relire plusieurs fois

Écrire du code aussi compact est très pratique à l'usage, mais pour un débutant il n'est pas nécessaire de savoir écrire de façon aussi concise.

grep : récupère une partie des éléments d'une liste

modifier

Se manipule comme map, et permet de récupérer une liste d'éléments contenus dans une liste suivant certaines conditions. Exemple : les éléments numériques inférieurs à 10 :

my @tableau_1_a_100 = ( 1 .. 100 );
my @inferieurs_a_10 = grep { $_ < 10 } @tableau_1_a_100 ;
say foreach @inferieurs_a_10; # affiche chaque élément de @inferieurs_a_10 suivit d'un retour à la ligne

defined : savoir si un élément de la liste est défini

modifier

exists : savoir si un élément d'une liste existe

modifier

Cette fonction permet de savoir si un élément d'une liste existe. Attention : ceci ne permet pas de savoir si l'élément est défini.

delete : supprimer un élément d'une table de hachage

modifier

keys : retourne toutes les clés d'une table de hachage

modifier

Renvoie une liste des clés d'une table de hachage.

my %hash = qw/ fruit poire légume carotte/;
say join(' : ', keys (%hash));

Affiche : « légume : fruit ».

values : retourne toutes les valeurs d'une table de hachage

modifier

Renvoie une liste des valeurs contenues dans une table de hachage.

my %hash = qw/ fruit poire légume carotte/;
say join(' : ', values(%hash));

each : retourne un couple clé-valeur d'une table de hachage

modifier

Cette fonction est très utile pour boucler sur tous les éléments d'un tableau associatif.

my %hash = qw/ fruit poire légume carotte/;
say "Un couple 'clé - valeur' : ", join( " - " , each %hash);

Affichera : « Un couple 'clé - valeur' : légume - carotte » .

pop : retire le dernier élément d'une liste et le retourne

modifier

Permet de supprimer le dernier élément d'une liste. Il retourne cet élément, donc on peut le récupérer.

my @fruits = qw/ poire cerise pomme fraise /;
say pop @fruits; # affichera "fraise"
# @fruits ne contient plus que "poire", "cerise" et "pomme"

push : ajoute à la fin de la liste un nouvel élément

modifier

Cette fonction ajoute un élément à la fin d'une liste.

On reprend l'exemple plus haut en ajoutant push pour remettre « fraise » :

my @fruits = qw/ poire cerise pomme fraise /;
say pop @fruits; # affichera "fraise"
# @fruits ne contient plus que "poire", "cerise" et "pomme"
push @fruits, "fraise"; # @fruits contient à nouveau "fraise" en dernière position

shift : supprime le premier élément d'une liste et le retourne

modifier

Il suffit de faire shift @tableau, exemple :

my @bon_a_manger = qw/fruit cerise légume patate /; # un simple tableau
my $aliment = shift @bon_a_manger;	# on supprime le premier élément du tableau et on le récupère (facultatif)
say $aliment; # affichera « fruit » qui était le premier élément de @bon_a_manger
say join ':', @bon_a_manger; # affichera « cerise:légume:patate »

unshift : ajoute un élément au début d'une liste

modifier

Exemple simple d'utilisation de unshift :

my @bon_a_manger = qw/fruit cerise légume patate /; # un simple tableau
my $aliment = "fromage"; # un simple scalaire
unshift @bon_a_manger, $aliment; # on ajoute le scalaire "fromage" au début du tableau @bon_a_manger
say join ':', @bon_a_manger; # affichera « fromage:fruit:cerise:légume:patate »

reverse : inverse tous les éléments d'une liste (le dernier devient premier, etc.)

modifier

On fait simplement reverse @tableau.

Le tri alphabétique inverse en devient on ne peut plus clair.

#!/usr/bin/perl -w
use strict;
my @tableau = qw(d a c e b);
my @tri = reverse sort @tableau; # e d c b a
print "@tri\n";#

splice : manipule des tranches de listes

modifier
#!/usr/bin/perl
use strict;
use warnings;
# splice est aux listes d‘items ce que
# substr est aux chaînes de caractères

# extraction
my @tableau= qw(ba be bi bo bu fa fe fi fo fu);
print splice (@tableau,2,3)."\n"; # bu dernier éliminé après bi et bo
print "@tableau\n";# ba be fa fe fi fo fu

# extraction du 5e à l'antépénultième
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,4,-2);
print "@tableau\n";# ba be bi bo fo fu

# comptage depuis la fin
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,-5,2);
print "@tableau\n";# ba be bi bo bu fi fo fu

# jusqu‘à l'avant-dernier
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,-4,-1);
print "@tableau\n";# ba be bi bo bu fa fu

# remplacement de 4 items par XX
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,2,4,"XX");
print "@tableau\n";# ba be XX fe fi fo fu

# gommage = remplacement vide
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,3,5);
print "@tableau\n";# ba be bi fo fu

# incrustation = remplacement sur une longueur de zéro
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,4,0,"YY");
print "@tableau\n";# ba be bi bo YY bu fa fe fi fo fu

# préfixage = fonction unshift
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
splice(@tableau,0,0,"PREF_");
print "@tableau\n";# PREF_ ba be bi bo bu fa fe fi fo fu

# suffixage = fonction push
@tableau= qw(ba be bi bo bu fa fe fi fo fu);
my $Nombre = @tableau;
splice(@tableau,$Nombre,0,"_SUFF");# ba be bi bo bu fa fe fi fo fu _SUFF
print "@tableau\n";

scalar : retourne le nombre d'éléments d'une liste

modifier

Cette fonction n'a aucune utilité si on est en contexte scalaire, par exemple :

$nb_elements = @tableau;

Cependant, lorsque nous sommes en contexte de liste, il sera déjà plus utile :

my @tableau_1 = qw/voiture avion vélo/;		# un tableau quelconque
my @tableau_2 = qw/train skateboard moto/;	# un second tableau quelconque

# ici, nous souhaitons stocker le nombre d'éléments de chaque tableau
# et ne pas simplement créer un tableau contenant toutes les valeurs des deux tableaux
my @nombres_elements = (scalar(@tableau_1), scalar(@tableau_2));

Ici, le code que nous avons créé permet de créer un tableau @nombres_elements qui contient le nombre d'éléments de deux précédents tableaux. Sans scalar, nous aurions un tableau contenant l'ensemble des scalaires des deux premiers tableaux. Cela est dû à l'aplatissement des tableaux.

sort : ordonne une liste

modifier
#!/usr/bin/perl
use strict;
use warnings;

my @tableau = qw(9 -.2 -4 34 -7 0 111);
# tri implicitement alphabétique
my @tri = sort @tableau;
print "@tri\n";# -.2 -4 -7 0 111 34 9

# tri explicitement alphabétique
@tri = sort ({$a cmp $b} @tableau);
print "@tri\n";# -.2 -4 -7 0 111 34 9

# tri inverse alphabétique
@tri = sort ({$b cmp $a} @tableau); # autre syntaxe : @tri = reverse sort @tableau;
print "@tri\n";# 9 34 111 0 -7 -4 -.2

# tri explicitement numérique
@tri = sort ({$a <=> $b} @tableau);
print "@tri\n";# -7 -4 -.2 0 9 34 111

# tri inverse numérique
@tri = sort ({$b <=> $a} @tableau);
print "@tri\n";# 111 34 9 0 -.2 -4 -7

# tris tarabiscotés sans intérêt autre que montrer les possibilités de "sort"

@tableau = qw(3 1 6 5 3 1 6 5);
# tri croissant sur une moitié, décroissant sur l‘autre
my $moitie = scalar @tableau / 2; # scalar est facultatif : my $... = environnement scalaire
@tri = ((sort ({$a <=> $b} splice (@tableau,0,$moitie))),(sort ({$b <=> $a} splice (@tableau,-$moitie,$moitie))));
print "@tri\n";# 1 3 5 6 6 5 3 1

@tableau = qw(9 -.2 -4 -14 -7 0 11);
# tri aux normes croissantes
@tri = sort ({abs $a <=> abs $b} @tableau);
print "@tri\n";# 0 -.2 -4 -7 9 11 -14

@tableau = qw(ab a abcd abc abcde);
# tri aux longueurs décroissantes
@tri = sort ({length $b <=> length $a} @tableau);
print "@tri\n";# abcde abcd abc ab a