Ответов (11)11
Вы можете сделать что-то вроде этого, как показано в perlfaq4 :
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @array = qw(one two three two three);
my @filtered = uniq(@array);
print "@filtered\n";
Выходы:
one two three
Если вы хотите использовать модуль, попробуйте uniq
функцию изList::MoreUtils
Установить List :: MoreUtils из CPAN
Затем в вашем коде:
use strict;
use warnings;
use List::MoreUtils qw(uniq);
my @dup_list = qw(1 1 1 2 3 4 4);
my @uniq_list = uniq(@dup_list);
Можно сделать с помощью простого Perl one liner.
my @in=qw(1 3 4 6 2 4 3 2 6 3 2 3 4 4 3 2 5 5 32 3); #Sample data
my @out=keys %{{ map{$_=>1}@in}}; # Perform PFM
print join ' ', sort{$a<=>$b} @out;# Print data back out sorted and in order.
Блок PFM делает это:
Данные в @in подаются в MAP. MAP строит анонимный хеш. Ключи извлекаются из хеша и передаются в @out
Метод 1: используйте хеш
Логика: хэш может иметь только уникальные ключи, поэтому перебирайте массив, присваивайте любое значение каждому элементу массива, сохраняя элемент как ключ этого хеша. Верните ключи хеша, это ваш уникальный массив.
my @unique = keys {map {$_ => 1} @array};
Метод 2: расширение метода 1 для повторного использования
Лучше создать подпрограмму, если мы должны использовать эту функцию в нашем коде несколько раз.
sub get_unique {
my %seen;
grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);
Метод 3: использовать модуль List::MoreUtils
use List::MoreUtils qw(uniq);
my @unique = uniq(@array);
Попробуйте это, похоже, для правильной работы функции uniq нужен отсортированный список.
use strict;
# Helper function to remove duplicates in a list.
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @teststrings = ("one", "two", "three", "one");
my @filtered = uniq @teststrings;
print "uniq: @filtered\n";
my @sorted = sort @teststrings;
print "sort: @sorted\n";
my @sortedfiltered = uniq sort @teststrings;
print "uniq sort : @sortedfiltered\n";
Предыдущие ответы в значительной степени обобщают возможные способы решения этой задачи.
Тем не менее, я предлагаю модификацию для тех , кто не заботится о подсчете дубликатов, но сделать заботу о порядке.
my @record = qw( yeah I mean uh right right uh yeah so well right I maybe );
my %record;
print grep !$record{$_} && ++$record{$_}, @record;
Обратите внимание, что ранее предложенное grep !$seen{$_}++ ...
приращение увеличивается $seen{$_}
до отрицания, поэтому приращение происходит независимо от того, было оно уже %seen
или нет. Однако вышесказанное $record{$_}
приводит к короткому замыканию, когда это правда, оставляя то, что когда-то было слышно, «не так %record
».
Вы также можете пойти на эту нелепость, которая использует преимущества автовивификации и существования хеш-ключей:
...
grep !(exists $record{$_} || undef $record{$_}), @record;
Однако это может привести к некоторой путанице.
И если вас не интересует ни порядок, ни количество дубликатов, вы можете использовать другой взлом, используя хеш-срезы и трюк, о котором я только что упомянул:
...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped
Документация Perl поставляется с хорошей коллекцией часто задаваемых вопросов. Ваш вопрос часто задают:
% perldoc -q duplicate
Ответ, скопированный и вставленный из вывода приведенной выше команды, появится ниже:
Находится в /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod Как удалить повторяющиеся элементы из списка или массива? (предоставлено brian d foy) Используйте хеш. Когда вы думаете, что слова "уникальный" или "повторяющийся", думайте «хеш-ключи». Если вас не волнует порядок элементов, вы можете просто создайте хеш, затем извлеките ключи. Не важно как ты создайте этот хеш: просто используйте «ключи» для получения уникальных элементов. мой% hash = map {$ _, 1} @array; # или хеш-фрагмент: @hash {@array} = (); # или foreach: $ hash {$ _} = 1 foreach (@array); мой @unique = keys% hash; Если вы хотите использовать модуль, попробуйте функцию "uniq" из "Список :: MoreUtils". В контексте списка он возвращает уникальные элементы, сохраняя свой порядок в списке. В скалярном контексте он возвращает количество уникальных элементов. используйте List :: MoreUtils qw (uniq); мой @unique = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 1,2,3,4,5,6,7 мой $ unique = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 7 Вы также можете просмотреть каждый элемент и пропустить те, которые вы видели до. Используйте хеш для отслеживания. В первый раз, когда цикл видит элемент, этот элемент не имеет ключа в% Seen. Оператор "следующий" создает ключ и сразу же использует его значение, равное "undef", поэтому цикл продолжает «толкать» и увеличивает значение для этого ключа. Следующий когда цикл видит тот же элемент, его ключ существует в хэше и значение для этого ключа истинно (поскольку оно не 0 или "undef"), поэтому next пропускает эту итерацию, и цикл переходит к следующему элементу. мой @unique = (); мой% видел = (); foreach мой $ elem (@array) { следующий, если $ видел {$ elem} ++; push @unique, $ elem; } Вы можете написать это более коротко, используя команду grep, которая делает то же самое вещь. мой% видел = (); мой @unique = grep {! $ замечен {$ _} ++} @array;