Відповіді:
Ви можете зробити щось подібне, як показано в 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::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