IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Des codes sources perlConsultez toutes les FAQ

Nombre d'auteurs : 13, nombre de questions : 59, dernière mise à jour : 27 mai 2011 

 
OuvrirSommaireGestions des tableaux (Array)

Il existe différentes méthodes pour supprimer les doublons dans une liste (un tableau) en perl. La première méthode consiste à utiliser un module Perl. C'est bien évidemment la méthode la plus recommandée car les modules disponibles sur le CPAN sont efficaces et bien écrits.
Voici une liste de modules intéressants :

La seconde méthode revient à ne pas utiliser de modules et coder soit même. Voici 3 procédures élégantes qui permettent de supprimer les doublons d'un tableau. Comparons les.

  1. Technique 1 (hash anonyme)

Cette procédure prend en argument une référence d'un tableau et chaque case du tableau devient une clé d'un hash anonyme. Les clés de la table de hachage sont renvoyées.

méthode 1
Sélectionnez
#!/usr/bin/perl
use strict;
use warnings;

sub doublons_hash_anonyme {
  my ($ref_tabeau) = @_;

  return keys %{ { map { $_ => 1 } @{$ref_tabeau} } };
}
  1. Technique 2 (tranche)

Cette procédure prend en argument une référence d'un tableau et chaque case du tableau devient la clé d'une tranche de hachage d'un hachage qu'on aura déclaré.

méthode 2
Sélectionnez
#!/usr/bin/perl
use strict;
use warnings;

sub doublons_tranche {
  my ($ref_tabeau) = @_;

  my %hash_sans_doublon;    # Comme un hash ne peut pas avoir deux clés identiques,
                            # utilser ces clé permet d'avoir un tableau unique
  @hash_sans_doublon{ @{$ref_tabeau} } = ();    # Pas besoin de surcharger le hash avec des valeurs inutiles
                                                # et ensuite, on renvoie le tableau des clés uniques
  return keys %hash_sans_doublon;
}
  1. Technique 3 (grep)

Cette procédure prend en argument une référence d'un tableau et chaque case est passée au filtre grep qui ne conserve que celles qui n'ont pas déjà été vues.

méthode 3
Sélectionnez
#!/usr/bin/perl
use strict;
use warnings;

sub doublons_grep {
  my ($ref_tabeau) = @_;

  my %hash_sans_doublon;

  return grep { !$hash_sans_doublon{$_}++ } @{$ref_tabeau};
}
  • Avantages et inconvénients

Ces trois techniques sont simples, efficaces et facilement maintenables. Il n'est pas du tout nécessaire d'installer un nouveau module pour cela, bien que List::Util soit dans le CORE de perl depuis sa version 5.8.
Pour de plus amples manipulations de tableaux, je vois recommande biensûr les modules cités ci-dessus.

Sachez maintenant que parmi ces 3 procédures, certaines sont plus rapides que d'autres. la technique 2 (à coup de tranche) est la plus rapide des 3, ensuite vient la technique 3 (à coup de grep), puis vient la dernière (technique 1). Ce n'est qu'une remarque, mais tout dépend de la longueur des listes, du nombre de doublons qu'elles contiennent, etc ... En général, la première place est toujours partagée entre la technique 2 (à coup de tranche) et 3 (à coup de grep).

Autres remarques :
- La technique 2 (tranche) est plus avantageuse que la 1 car elle n'a pas besoin de créer une liste intermédiaire.
- Notez bien que seule la technique 3 ( grep) permet de conserver l'ordre des éléments du tableau après suppression des doublons (important selon vos besoins) ! Sachez que la différence de temps entre la 2 et 3 n'est pas non plus dramatique. Utilisez le module Benchmark pour effectuer vos tests si vous le souhaitez.

  1. Exemple d'utilisation
Exemple
Sélectionnez
#!/usr/bin/perl
use strict;
use warnings;

my @listing_mots = qw/ moi 2Eurocents Woufeil toi djibril jedai moi jedai gldavid
  etc jedai stoyak lui nous tous je tu elle lui perl 10 20 20 30 8 6 9 100
  /;

my @resultat1 = doublons_hash_ano( \@listing_mots );
my @resultat2 = doublons_tranche( \@listing_mots );
my @resultat3 = doublons_grep( \@listing_mots );

print "Original : @listing_mots\n";
print "HASH anonyme : @resultat1\n";
print "Tranche : @resultat2\n";
print "GREP : @resultat3\n";

sub doublons_hash_anonyme {
  my ($ref_tabeau) = @_;

  return keys %{ { map { $_ => 1 } @{$ref_tabeau} } };
}

sub doublons_grep {
  my ($ref_tabeau) = @_;

  my %hash_sans_doublon;

  return grep { !$hash_sans_doublon{$_}++ } @{$ref_tabeau};
}

sub doublons_tranche {
  my ($ref_tabeau) = @_;

  my %hash_sans_doublon;    # Comme un hash ne peut pas avoir deux clés identiques,
                            # utilser ces clé permet d'avoir un tableau unique
  @hash_sans_doublon{ @{$ref_tabeau} } = ();    # Pas besoin de surcharger le hash avec des valeurs inutiles
                                                # et ensuite, on renvoie le tableau des clés uniques
  return keys %hash_sans_doublon;
}

sub doublons_hash_ano {
  my ($ref_tabeau) = @_;

  return keys %{ { map { $_ => 1 } @{$ref_tabeau} } };
}
Résultat
Sélectionnez
Original : moi 2Eurocents Woufeil toi djibril jedai moi jedai gldavid etc jedai stoyak lui nous tous je tu elle lui perl 10 20 20 30 8 6 9 100
HASH anonyme : djibril toi je gldavid etc tu Woufeil 30 100 moi 6 jedai 9 20 8 2Eurocents perl tous lui stoyak elle 10 nous
Tranche : djibril toi je gldavid etc tu Woufeil 30 100 moi 6 jedai 9 20 8 2Eurocents perl tous lui stoyak elle 10 nous
GREP : moi 2Eurocents Woufeil toi djibril jedai gldavid etc stoyak lui nous tous je tu elle perl 10 20 30 8 6 9 100

On peut constater que l'ordre est conservé pour la technique 3. Voilà, à vos tests. :-) !!

Mis à jour le 2010-04-07  par djibril

La fonction sort() en Perl est très puissante et permet de faire tous les tris inimaginables.
Elle trie les éléments d'une liste et retourne une liste triée des éléments fournis en paramètre.
Ces deux listes peuvent être distinctes, ou bien la liste d'origine peut être écrasée par le résultat du tri si elle est destinataire de l'affectation.
La fonction sort peut prendre un argument spécial qui est le bloc de comparaison à effectuer entre les éléments de la liste à trier. Il est ainsi possible de trier selon des critères tout à fait personnalisés.
Par défaut, le tri se fait dans l'ordre "lexicographique" (ordre alphabétique, étendu aux nombres dont les chiffres sont traités comme des caractères et non comme des nombres). Le bloc de comparaison personnalisé doit
être précisé entre accolades, avant la liste d'éléments à trier, sans être séparé de celle-ci par une virgule. Pour la comparaison, ce bloc utilise deux variables internes de PERL, $a et $b, qui ne sont définies que dans ce bloc et masquent toute variable $a ou $b propre à l'utilisateur. Ce bloc effectue donc un test quelconque, basé sur $a et $b, dont le résultat peut prendre trois valeurs :

  • positif si $a est avant $b dans l'ordre de tri souhaité
  • nul si $a et $b sont équivalents
  • négatif si $a est après $b dans l'ordre souhaité.

Ces trois valeurs de résultat de test correspondent aux résultats des opérateurs de test et cmp vus précédemment.
Ainsi, pour un tri lexicographique du tableau @t, on peut faire :

 
Sélectionnez
@l = sort ( @t ); ou bien @l = sort ( { $a cmp $b } @t );

qui a l'avantage d'être totalement explicite et donc plus clair à maintenir.
Pour un tri lexicographique inversé, on peut aussi bien écrire :

 
Sélectionnez
@l = reverse ( sort ( { $a cmp $b } @t ) );

que

 
Sélectionnez
@l = sort ( { $b cmp $a } @t );

Mais sachez que reverse est beaucoup plus optimal que faire sort ( { $b cmp $a } @t.
Pour un tri numérique :

 
Sélectionnez
@l = sort ( { $a <=> $b } @t );

Pour un tri un peu spécial, en supposant que @t contienne des indices d'un tableau et que l'on souhaite un tri de ces indices selon les valeurs numériques du tableau :

 
Sélectionnez
@l = sort ( { $tableau[$a] <=> $tableau[$b] } @t );

@l contient alors les valeurs de @t triées dans un ordre tel qu'elles indicent des valeurs croissantes dans @tableau. C'est très indirect et ce n'est pas forcément très naturel au début, mais c'est extrêmement puissant. Et pour finir, bien que l'on ait pas encore abordé la définition de fonctions personnalisées, il est possible d'appeler une fonction définie par le programmeur :

 
Sélectionnez
@l = sort ( { mafonction ($a, $b) } @t );

Nous vous recommandons de lire les articles ci dessous

les mongueurs de Perl (groupe francophone consacré à la promotion de Perl) ont écrit un très bon article.
En voici d'autres :
L'excellent article de Uri Guttman et Larry Rosler : A Fresh Look at Efficient Perl Sorting,
La traduction de cet article par votre serviteur les mongeurs est disponible ici.

Créé le 2008-12-05  par 2Eurocents

Il arrive que l'on ait besoin de comparer 2 listes perl entre elles afin d'obtenir les données communes aux deux listes, les données présentes dans une liste mais pas dans l'autre ... Pas besoin de reinventer la roue, il existe un module sur le CPAN qui le fait très bien, c'est List::CompareList::Compare. Voici un exemple de code :

 
Sélectionnez
#!/usr/bin/perl
use strict;
use warnings;
use List::Compare;

my @Llist = qw(abel abel baker camera delta edward fargo golfer);
my @Rlist = qw(baker camera delta delta edward fargo golfer hilton);

my $lc = List::Compare->new( \@Llist, \@Rlist );

my @intersection = $lc->get_intersection;
my @union        = $lc->get_union;

print "@intersection\n@union\n";
# baker camera delta edward fargo golfer
# abel baker camera delta edward fargo golfer hilton
Créé le 2011-01-06  par djibril
  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2011 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.