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 uniqfunção emList::MoreUtils
myléxico neste escopo, então tudo bem. Dito isto, possivelmente um nome de variável mais descritivo poderia ser escolhido.
$::ae $::bnã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_listdeve estar dentro da uniqchamada, 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::MoreUtilsuse 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 %seenou 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