Существует несколько библиотек, которые сравнивают массивы. Тем не менее, ваше сравнение включает в себя сложные структуры данных (массивы имеют хэш-ссылки в качестве элементов), и это по крайней мере усложняет использование всех известных мне модулей.
Итак, вот способ сделать это вручную. Я использую показанный массив и его копию с одним измененным значением.
use warnings;
use strict;
use feature 'say';
use List::Util qw(none); # in List::MoreUtils with older Perls
use Data::Dump qw(dd pp);
sub hr_eq {
my ($e1, $e2) = @_;
return 0 if scalar keys %$e1 != scalar keys %$e2;
foreach my $k1 (keys %$e1) {
return 0 if !exists($e2->{$k1}) or $e1->{$k1} ne $e2->{$k1};
}
return 1
}
my @a1 = (
{ 'title' => 'Legal Notice', 'created' => '2004-10-07 00:17:45', 'id' => 14 },
{ 'created' => '2004-11-15 16:04:06', 'id' => 86096, 'title' => 'IRC' },
{ 'id' => 16, 'created' => '2004-10-07 16:15:29', 'title' => 'About' }
);
my @a2 = (
{ 'title' => 'Legal Notice', 'created' => '2004-10-07 00:17:45', 'id' => 14 },
{ 'created' => '2004-11-15 16:xxx:06', 'id' => 86096, 'title' => 'IRC' },
{ 'id' => 16, 'created' => '2004-10-07 16:15:29', 'title' => 'About' }
);
my @only_in_two = grep {
my $e2 = $_;
none { hr_eq($e2, $_) } @a1;
} @a2;
dd \@only_in_two;
Это правильно идентифицирует элемент в @a2
, который не существует в @a1
(с xxx
в отметке времени).
Примечания
Это находит, что элементы одного массива не находятся в другом, а не полная разница между массивами. Это то, о чем конкретно спрашивает вопрос.
Сравнение основывается на деталях вашей структуры данных (hashref); от этого не уйти, если только вы не хотите использовать более полные библиотеки (например, Test::More
).
Используется сравнение строк, ne
, даже для чисел и временных меток. Посмотрите, имеет ли смысл в ваших реальных данных использовать более подходящие сравнения для конкретных элементов.
Поиск по всему списку для каждого элемента списка - это алгоритм O (N * M) . Решения такой (квадратичной) сложности пригодны для использования, пока данные не слишком велики; однако, как только данные становятся достаточно большими, чтобы увеличение размера имело явные эффекты, они быстро ломаются (замедляются до такой степени, что становятся бесполезными). Время, чтобы почувствовать это в вашем случае.
Здесь существует O (N + M) подход, использующий хэши, показанные в ответе икегами. Это намного лучше алгоритмически, если данные достаточно велики, чтобы их можно было показать. Однако, поскольку ваш массив содержит сложную структуру данных (hashrefs), нужно немного поработать, чтобы создать работающую программу, особенно если мы не знаем данных. Но если ваши данные значительны, вы наверняка захотите реализовать это.
Некоторые комментарии по фильтрации.
Вопрос правильно отмечает, что для каждого элемента массива, поскольку он обрабатывается в grep
, весь другой массив должен быть проверен.
Это делается в теле grep
с использованием none
из List :: Util . Он возвращает true, если код в его блоке оценивает false для всех элементов списка; таким образом, если «ни один» из элементов не удовлетворяет этому коду. Это основа требования: элемент не должен быть найден в другом массиве.
Требуется осторожность со стандартной $_
переменной , так как она используется как grep
и none
.
В блоке grep
$_
используется псевдоним текущего обрабатываемого элемента списка, так как grep
проходит через них один за другим; мы сохраняем его в именованную переменную ($e2
). Затем приходит none
и в своем блоке «вступает во владение» $_
, присваивая ему элементы @a1
по мере их обработки. Текущий элемент @a2
также доступен, так как мы скопировали его в $e2
.
Тест, выполненный в none
, помещается в подпрограмму, которую я называю hr_eq
, чтобы подчеркнуть, что она специально предназначена для сравнения на равенство (элементов в) хэш-ссылок.
Именно в этом сабе детали могут быть изменены. Во-первых, вместо того, чтобы прямо использовать ne
для значений для каждого ключа, вы можете добавить пользовательские сравнения для определенных ключей (числа должны использовать ==
и т. Д.). Затем, если ваши структуры данных изменятся, это то место, где вы будете корректировать специфику.