Как сравнить 2 массива и разбить на 3 группы? - PullRequest
1 голос
/ 24 марта 2011

Допустим, у меня есть эти массивы

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;

, и я хотел бы их сравнить, поэтому я получаю 3 новых массива, содержащих различия

  • , массив с элементами, которыенаходятся в @new, а не в @old: c
  • массиве с элементами, которых нет в @new, а в @old: f
  • массиве с элементами, которыенаходятся в @new и @old: abde

Я думаю о функции exists, но я полагаю, что она работает только для хэшей.

Обновление: Я перепутал примеры букв.

Ответы [ 6 ]

4 голосов
/ 24 марта 2011

ОБНОВЛЕНИЕ 2: Как указывает Майкл Карман, мой алгоритм потерпит неудачу, если элементы повторится.Таким образом, в фиксированном решении используется еще один хеш:

my (%count, %old);
$count{$_} = 1 for @new;
$old{$_}++ or $count{$_}-- for @old;
# %count is now really like diff(1)    

my (@minus, @plus, @intersection);
foreach (keys %count) {
    push @minus, $_        if $count{$_}  < 0;
    push @plus, $_         if $count{$_}  > 0;
    push @intersection, $_ if $count{$_} == 0;
};

ОБНОВЛЕНИЕ: похоже, что это решение также охватывает то, что в FAQ:

    push @difference, $_ if $count{$_};
    push @union, $_;
4 голосов
3 голосов
/ 24 марта 2011

Вот функция, которую я использовал много, много раз.

sub compute_sets {
    my ($ra, $rb) = @_;
    my (@a, @b, @ab, %a, %b, %seen);

    @a{@$ra} = ();
    @b{@$rb} = ();

    foreach (keys %a, keys %b) {
        next if $seen{$_}++;

        if (exists $a{$_} && exists $b{$_}) {
            push(@ab, $_);
        }
        elsif (exists $a{$_}) {
            push(@a, $_);
        }
        else {
            push(@b, $_);
        }
    }

    return(\@a, \@b, \@ab);
}

Возвращает ссылки на массивы, содержащие элементы в первом / втором / обоих списках:

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;

my ($new_only, $old_only, $both) = compute_sets(\@new, \@old);

say 'new only: ', join ' ', @$new_only; # c
say 'old only: ', join ' ', @$old_only; # f
say 'both: ', join ' ', @$both;         # e a b d
2 голосов
/ 25 марта 2011

Список :: Сравнить обрабатывает этот тип проблемы.

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

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;

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

# an array with the elements that are in @new and not in @old : c
my @Lonly = $lc->get_Lonly;
print "\@Lonly: @Lonly\n";

# an array with the elements that are not in @new and in @old : f
my @Ronly = $lc->get_Ronly;
print "\@Ronly: @Ronly\n";

# an array with the elements that are in both @new and @old : a b d e
my @intersection = $lc->get_intersection;
print "\@intersection: @intersection\n";

__END__
** prints

@Lonly: c
@Ronly: f
@intersection: a b d e
2 голосов
/ 24 марта 2011
1 голос
/ 24 марта 2011

Как насчет:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;
my %new = map{$_ => 1} @new;
my %old = map{$_ => 1} @old;

my (@new_not_old, @old_not_new, @new_and_old);
foreach my $key(@new) {
    if (exists $old{$key}) {
        push @new_and_old, $key;
    } else {
        push @new_not_old, $key;
    }
}
foreach my $key(@old) {
    if (!exists $new{$key}) {
        push @old_not_new, $key;
    }
}

print Dumper\@new_and_old;
print Dumper\@new_not_old;
print Dumper\@old_not_new;

Вывод:

$VAR1 = [
          'a',
          'b',
          'd',
          'e'
        ];
$VAR1 = [
          'c'
        ];
$VAR1 = [
          'f'
        ];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...