Risposte:
Puoi fare qualcosa del genere come dimostrato in perlfaq4 :
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @array = qw(one two three two three);
my @filtered = uniq(@array);
print "@filtered\n";
Uscite:
one two three
Se si desidera utilizzare un modulo, provare la uniq
funzione daList::MoreUtils
my
lessico in questo ambito, quindi va bene. Detto questo, potrebbe essere scelto un nome variabile più descrittivo.
$::a
e $::b
no?
sub uniq { my %seen; grep !$seen{$_}++, @_ }
è un'implementazione migliore poiché conserva l'ordine a costo zero. O ancora meglio, usa quello di List :: MoreUtils.
La documentazione Perl include una bella raccolta di domande frequenti. La tua domanda è frequente:
% perldoc -q duplicate
La risposta, copiata e incollata dall'output del comando sopra, appare sotto:
Trovato in /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod Come posso rimuovere elementi duplicati da un elenco o da un array? (contributo di brian d foy) Usa un hash. Quando pensi alle parole "unico" o "duplicato", pensa "chiavi hash". Se non ti interessa l'ordine degli elementi, potresti semplicemente creare l'hash quindi estrarre le chiavi. Non è importante come te crea quell'hash: basta usare le "chiavi" per ottenere gli elementi univoci. my% hash = map {$ _, 1} @array; # o una sezione hash: @hash {@array} = (); # o un foreach: $ hash {$ _} = 1 foreach (@array); my @unique = keys% hash; Se si desidera utilizzare un modulo, provare la funzione "uniq" da "list :: moreutils". Nel contesto dell'elenco restituisce gli elementi univoci, preservando il loro ordine nell'elenco. Nel contesto scalare, restituisce il numero di elementi unici. usa 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 Puoi anche passare attraverso ogni elemento e saltare quelli che hai visto prima. Usa un hash per tenere traccia. La prima volta che il loop vede un elemento, quell'elemento non ha chiave in% Visto. Viene creata l'istruzione "next" la chiave e usa immediatamente il suo valore, che è "undef", quindi il ciclo continua a "premere" e incrementa il valore per quel tasto. Il prossimo quando il loop vede lo stesso elemento, la sua chiave esiste nell'hash e il valore per quella chiave è vero (poiché non è 0 o "undef"), quindi il successivo salta quell'iterazione e il ciclo passa all'elemento successivo. my @unique = (); my% seen = (); foreach my $ elem (@array) { poi se $ visto {$ elem} ++; push @unique, $ elem; } Puoi scriverlo più brevemente usando un grep, che fa lo stesso cosa. my% seen = (); my @unique = grep {! $ seen {$ _} ++} @array;
Elenco di installazione :: MoreUtils da CPAN
Quindi nel tuo codice:
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
dovrebbe essere all'interno della uniq
chiamata, non@dups
Il mio solito modo di farlo è:
my %unique = ();
foreach my $item (@myarray)
{
$unique{$item} ++;
}
my @myuniquearray = keys %unique;
Se usi un hash e aggiungi gli elementi all'hash. Hai anche il vantaggio di sapere quante volte ogni elemento appare nell'elenco.
Può essere fatto con un semplice liner 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.
Il blocco PFM fa questo:
I dati in @in vengono inseriti in MAP. MAP crea un hash anonimo. Le chiavi vengono estratte dall'hash e inserite in @out
Logica: un hash può avere solo chiavi univoche, quindi iterare sull'array, assegnare qualsiasi valore a ciascun elemento dell'array, mantenendo l'elemento come chiave di quell'hash. Restituisce le chiavi dell'hash, è il tuo array unico.
my @unique = keys {map {$_ => 1} @array};
Meglio creare una subroutine se dovremmo usare questa funzionalità più volte nel nostro codice.
sub get_unique {
my %seen;
grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);
List::MoreUtils
use List::MoreUtils qw(uniq);
my @unique = uniq(@array);
Le risposte precedenti riassumono praticamente i possibili modi per svolgere questo compito.
Tuttavia, suggerisco una modifica per coloro che non si preoccupano di contare i duplicati, ma si preoccupano dell'ordine.
my @record = qw( yeah I mean uh right right uh yeah so well right I maybe );
my %record;
print grep !$record{$_} && ++$record{$_}, @record;
Si noti che gli grep !$seen{$_}++ ...
incrementi precedentemente suggeriti $seen{$_}
prima di annullare, quindi l'incremento si verifica indipendentemente dal fatto che sia già stato %seen
o meno. Quanto sopra, tuttavia, mette in corto circuito quando $record{$_}
è vero, lasciando ciò che è stato ascoltato una volta "spento %record
".
Potresti anche optare per questo ridicolo, che sfrutta l'autovivificazione e l'esistenza delle chiavi hash:
...
grep !(exists $record{$_} || undef $record{$_}), @record;
Ciò, tuttavia, potrebbe creare confusione.
E se non ti interessa né l'ordine né il conteggio dei duplicati, potresti fare un altro hack usando le porzioni di hash e il trucco che ho appena citato:
...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped
sub uniq{ my %seen; undef @seen{@_}; keys %seen; }
pulito.
Prova questo, sembra che la funzione uniq abbia bisogno di un elenco ordinato per funzionare correttamente.
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";
Utilizzando il concetto di chiavi hash uniche:
my @array = ("a","b","c","b","a","d","c","a","d");
my %hash = map { $_ => 1 } @array;
my @unique = keys %hash;
print "@unique","\n";
Uscita: acbd