55 votes

En Perl, existe-t-il un moyen intégré de comparer l'égalité de deux tableaux ?

J'ai deux tableaux de chaînes de caractères que je voudrais comparer pour vérifier l'égalité :

my @array1 = ("part1", "part2", "part3", "part4");
my @array2 = ("part1", "PART2", "part3", "part4");

Existe-t-il un moyen intégré de comparer des tableaux comme c'est le cas pour les scalaires ? J'ai essayé :

if (@array1 == @array2) {...}

mais il a juste évalué chaque tableau dans un contexte scalaire, et a donc comparé la longueur de chaque tableau.

Je peux créer ma propre fonction pour le faire, mais cela semble être une opération de si bas niveau qu'il devrait y avoir un moyen intégré de le faire. Est-ce le cas ?

Edit : malheureusement, je n'ai pas accès à la 5.10+ ou aux composants optionnels.

56voto

Sinan Ünür Points 76179

Il y a le nouveau opérateur de jumelage intelligent :

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;

my @x = (1, 2, 3);
my @y = qw(1 2 3);

say "[@x] and [@y] match" if @x ~~ @y;

Concernant Array::Compare :

En interne, le comparateur compare les deux tableaux en utilisant join pour transformer les deux tableaux en chaînes et en comparant les chaînes à l'aide de eq .

Je suppose que c'est une méthode valable, mais tant que nous utilisons des comparaisons de chaînes de caractères, je préférerais utiliser quelque chose comme :

#!/usr/bin/perl

use strict;
use warnings;

use List::AllUtils qw( each_arrayref );

my @x = qw(1 2 3);
my @y = (1, 2, 3);

print "[@x] and [@y] match\n" if elementwise_eq( \(@x, @y) );

sub elementwise_eq {
    my ($xref, $yref) = @_;
    return unless  @$xref == @$yref;

    my $it = each_arrayref($xref, $yref);
    while ( my ($x, $y) = $it->() ) {
        return unless $x eq $y;
    }
    return 1;
}

Si les tableaux que vous comparez sont de grande taille, les joindre va demander beaucoup de travail et consommer beaucoup de mémoire par rapport à la simple comparaison de chaque élément un par un.

Mise à jour : Bien sûr, il faut tester de telles affirmations. Des points de repère simples :

#!/usr/bin/perl

use strict;
use warnings;

use Array::Compare;
use Benchmark qw( cmpthese );
use List::AllUtils qw( each_arrayref );

my @x = 1 .. 1_000;
my @y = map { "$_" } 1 .. 1_000;

my $comp = Array::Compare->new;

cmpthese -5, {
    iterator => sub { my $r = elementwise_eq(\(@x, @y)) },
    array_comp => sub { my $r = $comp->compare(\(@x, @y)) },
};

C'est le pire scénario dans lequel elementwise_eq doit parcourir chaque élément des deux tableaux 1_000 fois et ça se voit :

             Rate   iterator array\_comp
iterator    246/s         --       -75%
array\_comp 1002/s       308%         --

D'un autre côté, le meilleur scénario est :

my @x = map { rand } 1 .. 1_000;
my @y = map { rand } 1 .. 1_000;

              Rate array\_comp   iterator
array\_comp   919/s         --       -98%
iterator   52600/s      5622%         --

iterator Cependant, les performances diminuent assez rapidement :

my @x = 1 .. 20, map { rand } 1 .. 1_000;
my @y = 1 .. 20, map { rand } 1 .. 1_000;

              Rate   iterator array\_comp
iterator   10014/s         --       -23%
array\_comp 13071/s        31%         --

Je n'ai pas regardé l'utilisation de la mémoire.

2 votes

@Bill merci, mais l'analyse n'est pas si approfondie. Elle fait le strict minimum pour m'apprendre à ne pas faire d'hypothèses sans mesure et que, dans la plupart des cas, vous pourriez faire pire que de Array::Compare .

2 votes

Simple my $i;for my $e (@$xref) {return unless $e eq $yref->[$i++];} est beaucoup plus rapide (v5.14.2).

13 votes

L'opérateur intelligent est déprécié dans la version 5.18 de Perl, sortie en mai 2013.

26voto

Ether Points 34103

Il y a Test::More La fonction is_deeply() de l'utilisateur, qui affichera également les endroits exacts où les structures diffèrent. Test::Deep eq_deeply(), qui ne nécessite pas de harnais de test (et renvoie simplement true ou false).

2 votes

Tu ne feras pas use modules destinés aux tests... sauf en cas de tests.

14voto

chaos Points 69029

Non intégré, mais il y a Array::Compare .

C'est l'une des opérations qui n'est pas prise en compte dans le noyau de Perl pour ce que je crois être des raisons didactiques - c'est-à-dire que si vous essayez de la faire, il y a probablement quelque chose qui ne va pas. L'exemple le plus illustratif de ceci, je pense, est l'absence d'un noyau read_entire_file En fait, fournir cette fonction dans le noyau conduirait les gens à penser qu'il s'agit d'une bonne idée Perl est conçu de manière à vous inciter à traiter les fichiers ligne par ligne, ce qui est généralement beaucoup plus efficace et constitue une meilleure idée, mais les programmeurs novices sont rarement à l'aise avec cette méthode et ont besoin d'être encouragés pour y parvenir.

La même chose s'applique ici : il existe probablement une bien meilleure façon d'effectuer la détermination que vous essayez d'accomplir en comparant deux tableaux. Pas nécessairement mais probablement. Perl vous incite donc à réfléchir à d'autres moyens d'atteindre votre objectif.

2 votes

Pour être un langage aussi expressif, Perl fait un excellent travail pour vous faire réfléchir à ce que vous faites.

0 votes

Tout comme le fait de fournir la fonction dump dans le noyau signifie que c'est une bonne idée de mourir au hasard et de laisser un noyau vide ?

0 votes

@chaos - c'est un point intéressant. J'essaie de faire correspondre mon emplacement dans une hiérarchie Xml avec un tableau obtenu à partir d'un fichier texte. (Pas de modules XPath, malheureusement).

9voto

David Harris Points 1902

Perl 5.10 vous offre l'opérateur smart match.

use 5.010;

if( @array1 ~~ @array2 )
{
    say "The arrays are the same";
}

Sinon, comme vous l'avez dit, vous devrez vous débrouiller tout seul.

4 votes

En fait, cela ne vous dira pas si les tableaux sont les mêmes, mais s'ils sont comparable .

3 votes

Pire encore, cela dépend si vous utilisez la version 5.10.0 ou 5.10.1+. En 5.10.0, il vérifie effectivement que les tableaux sont égaux.

6 votes

Je n'aime vraiment pas utiliser le terme "comparable" pour décrire le comportement de la correspondance intelligente sur les tableaux. Je le lis automatiquement comme "capable d'être comparé" (ce qui serait un comportement plutôt inutile) plutôt que comme "équivalent" (qui serait un bien meilleur terme, IMHO).

8voto

Quentin Points 325526

Tant que vous utilisez perl 5.10 ou une version plus récente, vous pouvez utiliser la fonction opérateur de jumelage intelligent .

if (@array1 ~~ @array2) {...}

4 votes

En fait, cela ne vous dira pas si les tableaux sont les mêmes, mais s'ils sont comparable .

0 votes

Voir "Le jumelage intelligent en détail" ( perldoc.perl.org/perlsyn.html#Smart-matching-in-detail ) Pour plus de détails sur ce que signifie "comparable". Habituellement cela signifie "Ouais, ils sont fondamentalement les mêmes".

2 votes

L'opérateur intelligent est déprécié dans la version 5.18 de Perl, sortie en mai 2013.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X