2010-04-07 12 views
7

Tengo dos matrices, @a y @b. Quiero hacer una comparación entre los elementos de las dos matrices.¿Cómo puedo comparar matrices en Perl?

my @a = qw"abc def efg ghy klm ghn"; 
my @b = qw"def ghy jgk lom com klm"; 

Si cualquier elemento coincide, establezca un indicador. ¿Hay alguna manera simple de hacer esto?

+4

Debido a que su pregunta no es clara, que está recibiendo dos tipos de respuestas: (1) los que la búsqueda de coincidencias de pares, como '$ a [$ i] eq $ b [$ i] '; y (2) aquellos que buscan cualquier coincidencia, como '$ a [$ i] eq $ b [$ j]'. ¿Cuál es tu objetivo? – FMc

+0

posible duplicado de http://stackoverflow.com/questions/1609467/in-perl-is-there-a-built-in-way-to-compare-two-arrays-for-equality –

+0

@Sinan: esa pregunta marcado como "posible duplicado" no es lo mismo que este. Se trata de comparar todos los elementos de dos matrices, pero esta se trata de encontrar un elemento común. –

Respuesta

9

En primer lugar, los 2 arrays necesitan ser escritas correctamente.

@a = ("abc","def","efg","ghy","klm","ghn"); 
@b = ("def","efg","ghy","klm","ghn","klm"); 

En segundo lugar, para las matrices arbitrarias (por ejemplo, matrices cuyos elementos pueden ser referencias a otras estructuras de datos) que puede utilizar Data::Compare.

Para matrices cuyos elementos son escalares, puede hacer una comparación usando List::MoreUtilspairwise BLOCK ARRAY1 ARRAY2, donde BLOCK es su subrutina de comparación. Puede emular pairwise (si usted no tiene una lista de acceso :: MoreUtils) a través de:

if (@a != @b) { 
    $equals = 0; 
} else { 
    $equals = 1; 
    foreach (my $i = 0; $i < @a; $i++) { 
     # Ideally, check for undef/value comparison here as well 
     if ($a[$i] != $b[$i]) { # use "ne" if elements are strings, not numbers 
           # Or you can use generic sub comparing 2 values 
      $equals = 0; 
      last; 
     } 
    } 
} 

P. S. No estoy seguro, pero List::Compare siempre puede ordenar las listas. No estoy seguro de si puede hacer comparaciones por parejas.

+0

Estás usando 'escalar' demasiado liberalmente para mi gusto. –

+0

Los operadores de comparación escalar imponen contexto escalar en sus argumentos. Entonces, '@a == @ b' es lo mismo que' escalar (@a) == escalar (@b) 'y' $ i <@ a' es lo mismo que '$ i

+0

Eso fue para la legibilidad de la demo ... casi nunca uso escalar() en el código de producción, por la sencilla razón de que no le gustó aquí. si crees que no ayuda mucho, puedo editarlo – DVK

1
my @a = qw' abc def efg ghy klm ghn '; 
my @b = qw' def ghy jgk lom com klm '; 

my $flag; 

foreach my $item(@a) { 
    $flag = @b~~$item ? 0 : 1; 
    last if !$flag; 
} 

Tenga en cuenta que necesitará Perl 5.10, o posterior, para utilizar el smart match operator (~~).

+0

Mike - ¿Esto funcionará antes de Perl 5.10? – DVK

+0

@DVK, no sé. Lo aprendí de Learning Perl. No necesito el uso de la declaración 5.010; pero tal vez solo sea factible después de Perl 5.10 . Lo verificaré. Todavía soy un aprendiz de Perl. Por favor, corrígeme si algo salió mal :) – Mike

+0

@DVK, el libro dice "operador inteligente de Perl 5.10". Pero parece que no lo hago t tiene que usar la declaración de uso 5.010; simplemente lo probé de nuevo y el uso de la declaración 5.010; es innecesario al menos con ActivePerl 5.10.0 en WinXP. Pero supongo que esto no funcionará antes de Perl 5.10. – Mike

1

Desde el requisito de que 'si cualquier partidos elemento' con la intersección de conjuntos:

sub set{ 
    my %set = map { $_, undef }, @_; 
    return sort keys %set; 
} 
sub compare{ 
    my ($listA,$listB) = @_; 
    return ((set(@$listA)-set(@$listB)) > 0) 
} 
+0

Esta pregunta está etiquetada como "perl". No quiero rechazarte sin advertirte primero ... –

+0

Ninguna pregunta es completamente específica del idioma. Estoy seguro de que alguien puede inventar una versión perl. También ilustra el punto general. –

+3

Sí, pero ¿qué pasa si un novato ve su respuesta, en este hilo etiquetado con Perl, sin ninguna notificación de que no es una respuesta de Perl, y lo ingresa, entonces se pregunta por qué no funciona? Lo único responsable de esta respuesta es rechazarla. Lo siento. –

2

Ésta es una manera:

use warnings; 
use strict; 
my @a = split /,/, "abc,def,efg,ghy,klm,ghn"; 
my @b = split /,/, "def,ghy,jgk,lom,com,klm"; 
my $flag = 0; 
my %a; 
@a{@a} = (1) x @a; 
for (@b) { 
    if ($a{$_}) { 
     $flag = 1; 
     last; 
    } 
} 
print "$flag\n"; 
+0

No es la lectura más fácil, pero me gusta. Al responder a una pregunta, me gusta explicar el comportamiento más fuera de lo normal, por lo que aprendemos en lugar de libros de cocina. – HerbN

+0

alguien puede explicar "@a {@a} = (1) x @a;"? –

+0

rellena las claves de '% a' con los elementos de' @ a', y los valores son todos 1. esto explota la tolerancia de Perl de diferentes tipos de variables con el mismo nombre, la porción hash y una matriz en contexto escalar. sin embargo, este código no funcionará para comparar matrices con valores no exclusivos – beasy

0

fuerza bruta debe hacer el truco para los pequeños a n:

my $flag = 0; 
foreach my $i (@a) { 
    foreach my $k (@b) { 
     if ($i eq $k) { 
      $flag = 1; 
      last; 
     } 
    } 
} 

Para la RGE n, utiliza una tabla hash:

my $flag = 0; 
my %aa  =(); 
    $aa{$_} = 1 foreach (@a); 
foreach my $i (@b) { 
    if ($aa{$i}) { 
     $flag = 1; 
     last; 
    } 
} 

Cuando un gran n es |@a| + |@b| > ~1000 artículos

4

de verificación para crear una función se cruzan, que devolverá una lista de elementos que están presentes en ambas listas. Entonces, su valor de retorno depende de la cantidad de elementos en la lista intersectada.

Puede encontrar fácilmente en la web la mejor implementación de interseccionar para Perl. Recuerdo haberlo buscado hace unos años.

Esto es lo que encontré:

 

my @array1 = (1, 2, 3); 
my @array2 = (2, 3, 4); 
my %original =(); 
my @isect =(); 

map { $original{$_} = 1 } @array1; 
@isect = grep { $original{$_} } @array2; 

0

en mi humilde opinión, se debe utilizar List::MoreUtils::pairwise. Sin embargo, si por alguna razón no puede, el siguiente sub devolverá un 1 por cada índice donde el valor en el primer conjunto se compare con el valor en el segundo conjunto.Puede generalizar este método tanto como desee y pasar su propio comparador si así lo desea, pero en ese punto, simplemente instalando List::MoreUtils sería un uso más productivo de su tiempo.

use strict; use warnings; 

my @a = qw(abc def ghi jkl); 
my @b = qw(abc dgh dlkfj jkl kjj lkm); 
my $map = which_ones_equal(\@a, \@b); 

print join(', ', @$map), "\n"; 

sub which_ones_equal { 
    my ($x, $y, $compare) = @_; 
    my $last = $#$x > $#$y ? $#$x : $#$y; 
    no warnings 'uninitialized'; 
    return [ map { 0 + ($x->[$_] eq $y->[$_]) } $[ .. $last ]; 
} 
0

Esto es Perl. La solución 'obvia':

my @a = qw"abc def efg ghy klm ghn"; 
my @b = qw"def ghy jgk lom com klm"; 
print "arrays equal\n" 
    if @a == @b and join("\0", @a) eq join("\0", @b); 

given "\ 0" not being in @a.

Pero gracias por confirmar que no hay otra solución genérica más que la suya.

0
my @a1 = qw|a b c d|; 
my @a2 = qw|b c d e|; 

for my $i (0..$#a1) { 
    say "element $i of array 1 was not found in array 2" 
     unless grep {$_ eq $a1[$i]} @a2 
} 
Cuestiones relacionadas