Відповіді:
Ви можете зробити щось подібне, як показано в 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{$_}++, @_ }це краща реалізація, оскільки вона береже порядок без витрат. Або ще краще, скористайтеся списком зі списку :: MoreUtils.
Документація Perl постачається з приємною колекцією поширених запитань. Ваше запитання часто задається:
% perldoc -q duplicate
Відповідь, скопійована та вставлена з результату команди вище, відображається нижче:
Знайдено в /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod
Як я можу видалити повторювані елементи зі списку чи масиву?
(сприяв Брайан d foy)
Використовуйте хеш. Коли ви думаєте, що слова "унікальні" або "дублюються", подумайте
"хеш-ключі".
Якщо вам не байдуже порядок елементів, ви могли просто
створити хеш, потім витягнути ключі. Не важливо, як ти
Створіть цей хеш: просто ви використовуєте "клавіші", щоб отримати унікальні елементи.
мій% хеш = карта {$ _, 1} @array;
# або хеш-фрагмент: @hash {@array} = ();
# або foreach: $ hash {$ _} = 1 foreach (@array);
мій @unique = ключі% хеш;
Якщо ви хочете використовувати модуль, спробуйте функцію "uniq" від
"Список :: MoreUtils". У контексті списку він повертає унікальні елементи,
збереження їх порядку в списку. У скалярному контексті він повертає
кількість унікальних елементів.
використовувати Список :: MoreUtils qw (uniq);
мій @unique = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 1,2,3,4,5,6,7
мій $ унікальний = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); №7
Ви також можете пройти кожен елемент і пропустити ті, які ви бачили
раніше. Використовуйте хеш для відстеження. Перший раз, коли цикл бачить
елемент, у цього елемента немає ключа в% Seen. "Наступний" заява створює
ключ і негайно використовує його значення, яке є "undef", тому цикл
продовжує "натискати" і збільшує значення для цієї клавіші. Наступний
Коли цикл бачить той самий елемент, його ключ існує в хеші та
значення для цього ключа є істинним (оскільки це не 0 або "undef"), тож
Наступний пропускає цю ітерацію і цикл переходить до наступного елемента.
мій @unique = ();
мій% бачив = ();
передбачити мій $ elem (@array)
{
наступний, якщо $ saw {$ elem} ++;
push @unique, $ elem;
}
Ви можете написати це коротше, використовуючи греп, який робить те саме
річ.
мій% бачив = ();
мій @unique = grep {! $ saw {$ _} ++} @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 one.
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::MoreUtilsuse 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