2008-08-11 8 views

ответ

145

Вы можете сделать что-то вроде этого, как показано в 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

+27

пожалуйста, не используйте $ а или $ Ь в примерах, как они волшебные Глобалы из рода() – szabgab 2008-09-17 07:50:06

+2

Это `my` лексической в ​​этом scope, так что это нормально. При этом может быть выбрано более описательное имя переменной. – ephemient 2010-01-18 17:51:13

+2

@ephemient да, но если бы вы добавили сортировку в эту функцию, тогда она бы превзошла `$ :: a` и` $ :: b`, не так ли? – vol7ron 2012-02-21 16:45:38

20

Мои Обычный способ сделать это:

my %unique =(); 
foreach my $item (@myarray) 
{ 
    $unique{$item} ++; 
} 
my @myuniquearray = keys %unique; 

Если вы используете хэш и добавляете элементы в хэш. У вас также есть бонус узнать, сколько раз каждый элемент появляется в списке.

115

Документация Perl поставляется с хорошей коллекцией часто задаваемых вопросов. Часто задают Ваш вопрос:

% perldoc -q duplicate 

Ответ, копировать и вставлять из вывода выше команды, приводится ниже:

Found in /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod 
How can I remove duplicate elements from a list or array? 
    (contributed by brian d foy) 

    Use a hash. When you think the words "unique" or "duplicated", think 
    "hash keys". 

    If you don't care about the order of the elements, you could just 
    create the hash then extract the keys. It's not important how you 
    create that hash: just that you use "keys" to get the unique elements. 

     my %hash = map { $_, 1 } @array; 
     # or a hash slice: @hash{ @array } =(); 
     # or a foreach: $hash{$_} = 1 foreach (@array); 

     my @unique = keys %hash; 

    If you want to use a module, try the "uniq" function from 
    "List::MoreUtils". In list context it returns the unique elements, 
    preserving their order in the list. In scalar context, it returns the 
    number of unique elements. 

     use 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 

    You can also go through each element and skip the ones you've seen 
    before. Use a hash to keep track. The first time the loop sees an 
    element, that element has no key in %Seen. The "next" statement creates 
    the key and immediately uses its value, which is "undef", so the loop 
    continues to the "push" and increments the value for that key. The next 
    time the loop sees that same element, its key exists in the hash and 
    the value for that key is true (since it's not 0 or "undef"), so the 
    next skips that iteration and the loop goes to the next element. 

     my @unique =(); 
     my %seen =(); 

     foreach my $elem (@array) 
     { 
     next if $seen{ $elem }++; 
     push @unique, $elem; 
     } 

    You can write this more briefly using a grep, which does the same 
    thing. 

     my %seen =(); 
     my @unique = grep { ! $seen{ $_ }++ } @array; 
63

Установка 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); 
3

Последнее, что было довольно хорошо. Я бы немного изменил его:

my @arr; 
my @uniqarr; 

foreach my $var (@arr){ 
    if (! grep(/$var/, @uniqarr)){ 
    push(@uniqarr, $var); 
    } 
} 

Я думаю, что это, вероятно, самый читаемый способ сделать это.

6

Переменная @array список с повторяющимися элементами

%seen=(); 
@unique = grep { ! $seen{$_} ++ } @array; 
5

Может быть сделано с простой 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. 

Блок ЧИМ делает это:

Данные в @in подается в MAP. MAP создает анонимный хэш. Ключи извлекаются из хэша и подаются в @out

0

Попробуйте это, кажется, что функция 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"; 
1

Используя понятие уникальных ключей хеш:

my @array = ("a","b","c","b","a","d","c","a","d"); 
my %hash = map { $_ => 1 } @array; 
my @unique = keys %hash; 
print "@unique","\n"; 

Выход: ACBD

1

Метод 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);