Ответы:
Вы можете сделать что-то вроде этого, как показано в 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
my
лексическое в этом смысле, так что все в порядке. При этом, возможно, можно было бы выбрать более описательное имя переменной.
$::a
и $::b
не так ли?
sub uniq { my %seen; grep !$seen{$_}++, @_ }
это лучшая реализация, поскольку она сохраняет порядок без затрат. Или даже лучше, используйте тот из List :: MoreUtils.
Документация Perl поставляется с хорошей коллекцией часто задаваемых вопросов. Ваш вопрос часто задают:
% perldoc -q duplicate
Ответ, скопированный и вставленный из вывода команды выше, появляется ниже:
Найдено в /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod Как я могу удалить дубликаты элементов из списка или массива? (предоставлено Брайаном Д. Фой) Используйте хэш. Когда вы думаете, слова «уникальный» или «дублированный», подумайте "ключи хеша". Если вы не заботитесь о порядке элементов, вы можете просто создайте хеш, затем извлеките ключи. Не важно как ты создайте этот хэш: просто используйте «ключи» для получения уникальных элементов. мой% hash = map {$ _, 1} @array; # или фрагмент хеша: @hash {@array} = (); # или foreach: $ hash {$ _} = 1 foreach (@array); мой @unique = keys% hash; Если вы хотите использовать модуль, попробуйте функцию "uniq" из "Список :: MoreUtils". В контексте списка он возвращает уникальные элементы, сохраняя их порядок в списке. В скалярном контексте возвращает количество уникальных элементов. использовать List :: MoreUtils qw (uniq); my @unique = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 1,2,3,4,5,6,7 my $ unique = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); № 7 Вы также можете пройти через каждый элемент и пропустить те, которые вы видели перед. Используйте хеш для отслеживания. Первый раз, когда цикл видит элемент, этот элемент не имеет ключа в% Seen. «Следующее» утверждение создает ключ и сразу же использует его значение, которое является "undef", поэтому цикл продолжает нажимать и увеличивает значение для этой клавиши. Следующий Когда цикл видит тот же элемент, его ключ существует в хеше и значение для этого ключа является истинным (так как это не 0 или "undef"), поэтому next пропускает эту итерацию, и цикл переходит к следующему элементу. my @unique = (); мой% видел = (); foreach мой $ elem (@array) { далее, если $ seen {$ elem} ++; push @unique, $ elem; } Вы можете написать это более кратко, используя grep, который делает то же самое вещь. мой% видел = (); мой @unique = grep {! $ seen {$ _} ++} @array;
Список установки :: 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);
@dup_list
должен быть внутри uniq
звонка, а не@dups
Мой обычный способ сделать это:
my %unique = ();
foreach my $item (@myarray)
{
$unique{$item} ++;
}
my @myuniquearray = keys %unique;
Если вы используете хеш и добавляете элементы в хеш. Вы также можете узнать, сколько раз каждый элемент появляется в списке.
Может быть сделано с простым Perl одним вкладышем.
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
Логика: хеш может иметь только уникальные ключи, поэтому итерируйте по массиву, присваивайте любое значение каждому элементу массива, сохраняя элемент в качестве ключа этого хеша. Вернуть ключи хеша, это ваш уникальный массив.
my @unique = keys {map {$_ => 1} @array};
Лучше создать подпрограмму, если мы должны использовать эту функцию несколько раз в нашем коде.
sub get_unique {
my %seen;
grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);
List::MoreUtils
use List::MoreUtils qw(uniq);
my @unique = uniq(@array);
Предыдущие ответы в значительной степени суммируют возможные пути выполнения этой задачи.
Тем не менее, я предлагаю модификацию для тех , кто не заботится о подсчете дубликатов, но сделать заботу о порядке.
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
sub uniq{ my %seen; undef @seen{@_}; keys %seen; }
аккуратно.
Попробуйте, кажется, что для правильной работы функции 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 @array = ("a","b","c","b","a","d","c","a","d");
my %hash = map { $_ => 1 } @array;
my @unique = keys %hash;
print "@unique","\n";
Выход: acbd