Respostas:
Você pode fazer algo assim, como demonstrado no perlfaq4 :
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @array = qw(one two three two three);
my @filtered = uniq(@array);
print "@filtered\n";
Saídas:
one two three
Se você deseja usar um módulo, tente a uniq
função emList::MoreUtils
my
léxico neste escopo, então tudo bem. Dito isto, possivelmente um nome de variável mais descritivo poderia ser escolhido.
$::a
e $::b
não seria?
sub uniq { my %seen; grep !$seen{$_}++, @_ }
é uma implementação melhor, pois preserva a ordem sem nenhum custo. Ou melhor ainda, use o da List :: MoreUtils.
A documentação do Perl vem com uma boa coleção de perguntas frequentes. Sua pergunta é freqüente:
% perldoc -q duplicate
A resposta, copie e cole a partir da saída do comando acima, aparece abaixo:
Encontrado em /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod Como posso remover elementos duplicados de uma lista ou matriz? (contribuído por brian d foy) Use um hash. Quando você acha que as palavras "único" ou "duplicado", pense "chaves de hash". Se você não se importa com a ordem dos elementos, pode apenas crie o hash e extraia as chaves. Não é importante como você crie esse hash: apenas use "chaves" para obter os elementos exclusivos. meu% hash = mapa {$ _, 1} @array; # ou uma fatia de hash: @hash {@array} = (); # ou um foreach: $ hash {$ _} = 1 foreach (@array); meu @ único = chaves% hash; Se você deseja usar um módulo, tente a função "uniq" em "Lista :: MoreUtils". No contexto da lista, ele retorna os elementos exclusivos, preservando sua ordem na lista. No contexto escalar, ele retorna o número de elementos únicos. use List :: MoreUtils qw (uniq); my @unique = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 1,2,3,4,5,6,7 meu $ unique = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 7 Você também pode percorrer cada elemento e pular os que você viu antes. Use um hash para acompanhar. A primeira vez que o loop vê um elemento, esse elemento não tem chave em% visto. A instrução "next" cria a chave e imediatamente usa seu valor, que é "undef", então o loop continua com o "push" e incrementa o valor dessa chave. Nas próximas Quando o loop vê o mesmo elemento, sua chave existe no hash e o valor dessa chave é verdadeiro (já que não é 0 ou "undef"), portanto, o next pula essa iteração e o loop passa para o próximo elemento. meu @ único = (); meu% visto = (); foreach meu $ elem (@array) { próximo se $ seen {$ elem} ++; push @unique, $ elem; } Você pode escrever isso mais rapidamente usando um grep, que faz o mesmo coisa. meu% visto = (); meu @ único = grep {! $ seen {$ _} ++} @array;
Lista de instalação :: MoreUtils from CPAN
Então no seu código:
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
deve estar dentro da uniq
chamada, não@dups
Minha maneira usual de fazer isso é:
my %unique = ();
foreach my $item (@myarray)
{
$unique{$item} ++;
}
my @myuniquearray = keys %unique;
Se você usar um hash e adicionar os itens ao hash. Você também tem o bônus de saber quantas vezes cada item aparece na lista.
Pode ser feito com um liner Perl simples.
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.
O bloco PFM faz isso:
Os dados em @in são alimentados no MAP. O MAP cria um hash anônimo. As chaves são extraídas do hash e alimentam @out
Lógica: um hash pode ter apenas chaves exclusivas; portanto, itere sobre a matriz, atribua qualquer valor a cada elemento da matriz, mantendo o elemento como chave desse hash. Retorne as chaves do hash, é sua matriz exclusiva.
my @unique = keys {map {$_ => 1} @array};
Melhor criar uma sub-rotina se devemos usar essa funcionalidade várias vezes em nosso código.
sub get_unique {
my %seen;
grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);
List::MoreUtils
use List::MoreUtils qw(uniq);
my @unique = uniq(@array);
As respostas anteriores resumem bastante as maneiras possíveis de realizar essa tarefa.
No entanto, sugiro uma modificação para aqueles que não se preocupam contando os duplicados, mas fazer o cuidado sobre a ordem.
my @record = qw( yeah I mean uh right right uh yeah so well right I maybe );
my %record;
print grep !$record{$_} && ++$record{$_}, @record;
Observe que os grep !$seen{$_}++ ...
incrementos sugeridos anteriormente $seen{$_}
antes de negar, portanto, o incremento ocorre independentemente de já ter sido %seen
ou não. O exposto acima, no entanto, provoca um curto-circuito quando $record{$_}
é verdade, deixando o que foi ouvido uma vez "fora do ar %record
".
Você também pode usar esse ridículo, que tira proveito da autovivificação e da existência de chaves de hash:
...
grep !(exists $record{$_} || undef $record{$_}), @record;
Isso, no entanto, pode levar a alguma confusão.
E se você não se importa com pedidos ou contagens duplicadas, pode fazer outro hack usando fatias de hash e o truque que acabei de mencionar:
...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped
sub uniq{ my %seen; undef @seen{@_}; keys %seen; }
Neat.
Tente isso, parece que a função uniq precisa de uma lista classificada para funcionar corretamente.
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";
Usando o conceito de chaves de hash exclusivas:
my @array = ("a","b","c","b","a","d","c","a","d");
my %hash = map { $_ => 1 } @array;
my @unique = keys %hash;
print "@unique","\n";
Saída: acbd