Wie entferne ich doppelte Elemente aus einem Array in Perl?
-
08-06-2019 - |
Frage
Ich habe ein Array in Perl:
my @my_array = ("one","two","three","two","three");
Wie entferne ich die Duplikate aus dem Array?
Lösung
Sie können so etwas tun, wie in gezeigt perlfaq4:
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @array = qw(one two three two three);
my @filtered = uniq(@array);
print "@filtered\n";
Ausgänge:
one two three
Wenn Sie ein Modul verwenden möchten, probieren Sie es aus uniq
Funktion von List::MoreUtils
Andere Tipps
Die Perl-Dokumentation enthält eine schöne Sammlung von FAQs.Ihre Frage wird häufig gestellt:
% perldoc -q duplicate
Die Antwort, kopiert und eingefügt aus der Ausgabe des obigen Befehls, erscheint unten:
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;
Installieren List::MoreUtils von CPAN
Dann in Ihrem Code:
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);
Meine übliche Vorgehensweise ist:
my %unique = ();
foreach my $item (@myarray)
{
$unique{$item} ++;
}
my @myuniquearray = keys %unique;
Wenn Sie einen Hash verwenden und die Elemente zum Hash hinzufügen.Sie haben außerdem den Vorteil, dass Sie wissen, wie oft jedes Element in der Liste vorkommt.
Kann mit einem einfachen Perl-Einzeiler durchgeführt werden.
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.
Der PFM-Block macht Folgendes:
Daten in @in werden in MAP eingespeist.MAP erstellt einen anonymen Hash.Schlüssel werden aus dem Hash extrahiert und in @out eingespeist
Die Variable @array ist die Liste mit doppelten Elementen
%seen=();
@unique = grep { ! $seen{$_} ++ } @array;
Das letzte war ziemlich gut.Ich würde es einfach ein wenig anpassen:
my @arr;
my @uniqarr;
foreach my $var ( @arr ){
if ( ! grep( /$var/, @uniqarr ) ){
push( @uniqarr, $var );
}
}
Ich denke, das ist wahrscheinlich die am besten lesbare Art und Weise, es zu tun.
Methode 1:Verwenden Sie einen Hash
Logik:Ein Hash kann nur eindeutige Schlüssel haben, also iterieren Sie über das Array, weisen Sie jedem Element des Arrays einen beliebigen Wert zu und behalten Sie das Element als Schlüssel dieses Hashs bei.Rückgabeschlüssel des Hashs, es ist Ihr einzigartiges Array.
my @unique = keys {map {$_ => 1} @array};
Methode 2:Erweiterung der Methode 1 zur Wiederverwendbarkeit
Wenn wir diese Funktionalität in unserem Code mehrmals verwenden möchten, ist es besser, eine Unterroutine zu erstellen.
sub get_unique {
my %seen;
grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);
Methode 3:Modul verwenden List::MoreUtils
use List::MoreUtils qw(uniq);
my @unique = uniq(@array);
Frühere Antworten fassen die möglichen Wege zur Lösung dieser Aufgabe ziemlich genau zusammen.
Ich schlage jedoch eine Modifikation für diejenigen vor, die nicht Wert darauf legen Zählen die Duplikate, aber Tun auf Ordnung achten.
my @record = qw( yeah I mean uh right right uh yeah so well right I maybe );
my %record;
print grep !$record{$_} && ++$record{$_}, @record;
Beachten Sie, dass das zuvor vorgeschlagene grep !$seen{$_}++ ...
Schritte $seen{$_}
vor der Negierung, daher erfolgt die Inkrementierung unabhängig davon, ob sie bereits erfolgt ist %seen
oder nicht.Das oben Gesagte führt jedoch zu Kurzschlüssen $record{$_}
ist wahr, das Gehörte einmal wegzulassen %record
'.
Sie könnten sich auch für diese Lächerlichkeit entscheiden, die sich die Autovivifizierung und die Existenz von Hash-Schlüsseln zunutze macht:
...
grep !(exists $record{$_} || undef $record{$_}), @record;
Das könnte jedoch zu Verwirrung führen.
Und wenn Ihnen weder die Reihenfolge noch die Anzahl der Duplikate wichtig sind, können Sie einen weiteren Hack verwenden, indem Sie Hash-Slices und den Trick verwenden, den ich gerade erwähnt habe:
...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped
Versuchen Sie dies, anscheinend benötigt die Uniq-Funktion eine sortierte Liste, um ordnungsgemäß zu funktionieren.
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";
Verwendung des Konzepts eindeutiger Hash-Schlüssel:
my @array = ("a","b","c","b","a","d","c","a","d");
my %hash = map { $_ => 1 } @array;
my @unique = keys %hash;
print "@unique","\n";
Ausgabe:a c b d