Domanda

Ho un array in Perl:

my @my_array = ("one","two","three","two","three");

Come rimuovo i duplicati dall'array?

È stato utile?

Soluzione

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 vuoi usare un modulo, prova il file uniq funzione da List::MoreUtils

Altri suggerimenti

La documentazione Perl viene fornita con una bella raccolta di FAQ.La tua domanda viene posta frequentemente:

% perldoc -q duplicate

La risposta, copiata e incollata dall'output del comando sopra, appare di seguito:

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;

Installare Elenco::MoreUtils dal 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);

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 ciascun elemento appare nell'elenco.

Può essere fatto con un semplice one-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

La variabile @array è la lista con elementi duplicati

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

Quest'ultimo era piuttosto buono.Lo modificherei solo un po':

my @arr;
my @uniqarr;

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

Penso che questo sia probabilmente il modo più leggibile per farlo.

Metodo 1:Usa un hash

Logica:Un hash può avere solo chiavi univoche, quindi scorrere l'array, assegnare qualsiasi valore a ciascun elemento dell'array, mantenendo l'elemento come chiave di quell'hash.Restituisci le chiavi dell'hash, è il tuo array unico.

my @unique = keys {map {$_ => 1} @array};

Metodo 2:Estensione del metodo 1 per la riusabilità

È meglio creare una subroutine se dobbiamo utilizzare questa funzionalità più volte nel nostro codice.

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

Metodo 3:Usa il modulo List::MoreUtils

use List::MoreUtils qw(uniq);
my @unique = uniq(@array);

Le risposte precedenti riassumono praticamente le possibili modalità per eseguire questo compito.

Tuttavia, suggerisco una modifica per coloro che non preoccuparsi conteggio i duplicati, ma Fare preoccupatevi 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 quanto suggerito in precedenza grep !$seen{$_}++ ... incrementi $seen{$_} prima di negare, quindi l'incremento avviene indipendentemente dal fatto che sia già avvenuto %seen o no.Quanto sopra, tuttavia, cortocircuita quando $record{$_} è vero, lasciando fuori ciò che è stato ascoltato una volta %record'.

Potresti anche optare per questa ridicolaggine, che sfrutta l'autovivificazione e l'esistenza delle chiavi hash:

...
grep !(exists $record{$_} || undef $record{$_}), @record;

Ciò, tuttavia, potrebbe creare una certa confusione.

E se non ti interessa né l'ordine né il conteggio dei duplicati, potresti fare un altro trucco usando le fette di hash e il trucco che ho appena menzionato:

...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped

Prova questo, sembra che la funzione uniq necessiti 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 univoche:

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

Produzione:acbd

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top