Разница между двумя массивами с помощью утилиты perl array_diff - PullRequest
2 голосов
/ 02 мая 2020

Я пытаюсь запустить array_diff для 2 массивов.

sub array_diff(\@\@) {
    my %e = map { $_ => undef } @{$_[1]};
    return @{[
        ( grep { (exists $e{$_}) ? ( delete $e{$_} ) : ( 1 ) } @{ $_[0] } ),
        keys %e
    ] };
}

my $col = 'col';
my $stg = 'stg';
my @blocks = qw( block1 block2 block3 block4 block5 );
my %hash; @{$hash{$col}{$stg}} = qw( block1 block2 block3 );

my @diff = array_diff(@all_blocks, @{$hash{$col}{$stg}});
print ("diff : @diff\n");

При выполнении вышеуказанной строки выдается следующая ошибка:

Possible unintended interpolation of @diff in string at get_blocks.pl line 56.
Type of arg 2 to main::array_diff must be array (not reference constructor) at get_blocks.pl line 55, near "})"
syntax error at get_blocks.pl line 55, near "})"
Execution of get_blocks.pl aborted due to compilation errors.

Однако, когда я пытаюсь сделать то же самое без массива ha sh, он работает

my @a = qw( a b c d e);
my @b = qw( c d  );

sub array_diff(\@\@) {
    my %e = map { $_ => undef } @{$_[1]};
    return @{[
        ( grep { (exists $e{$_}) ? ( delete $e{$_} ) : ( 1 ) } @{ $_[0] } ),
        keys %e
    ] };
}
# symmetric difference
my @diff = array_diff(@a, @b);
print ("diff : @diff\n");

Результат:

diff : a b e

1 Ответ

4 голосов
/ 02 мая 2020

Мы можем проконсультироваться perldiag , чтобы выяснить ошибки и предупреждения.

Possible unintended interpolation of @diff in string at get_blocks.pl line 56.

(W неоднозначно) Вы сказали что-то вроде '@foo 'в строке в двойных кавычках, но в то время в области видимости не было массива @foo. Если вам нужен литерал @foo, напишите его как \@foo; в противном случае выясните, что случилось с массивом, который вы явно потеряли.

Вы делаете "@diff", но @diff не объявлено.

Type of arg 2 to main::array_diff must be array (not reference constructor) at get_blocks.pl line 55, near "})"

(F) Эта функция требует, чтобы аргумент в этой позиции был определенного типа. Массивы должны быть @NAME или @ {EXPR}. Хэши должны быть% NAME или% {EXPR}. Неявная разыменование не допускается - используйте формы {EXPR} в качестве явной разыменования. См. Perlref.

Как и сказано, прототип \@ должен принимать массив, а не ссылку.

# Bad
array_diff([1,2,3], [4,5,6]);

# Good
array_diff(@{[1,2,3]}, @{[4,5,6]});

Ваш пример кода и ваши ошибки не совпадают. @diff объявлено, и вы удалили ссылку $hash{$col}{$stg}.


Я бы рекомендовал не использовать прототипы. Они не похожи на объявление аргументов функции на других языках. Вместо этого они предназначены для эмуляции магического поведения встроенных функций c.

Вместо этого передайте ссылки.

my @diff = array_diff(\@all_blocks, $hash{$col}{$stg});

Подлинные сигнатуры подпрограмм к сожалению, все еще экспериментальные.


Нет необходимости в операторе детской тележки @{[]} вокруг grep. grep уже возвращает новый массив, нет необходимости его клонировать. Это усложняет код и тратит память.

...