ฉันมีอาร์เรย์ใน Perl:
my @my_array = ("one","two","three","two","three");
ฉันจะลบรายการที่ซ้ำออกจากอาร์เรย์ได้อย่างไร
ฉันมีอาร์เรย์ใน Perl:
my @my_array = ("one","two","three","two","three");
ฉันจะลบรายการที่ซ้ำออกจากอาร์เรย์ได้อย่างไร
คำตอบ:
คุณสามารถทำสิ่งนี้ตามที่แสดงในperlfaq4 :
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @array = qw(one two three two three);
my @filtered = uniq(@array);
print "@filtered\n";
ขาออก:
one two three
หากคุณต้องการใช้โมดูลให้ลองใช้uniq
ฟังก์ชันจากList::MoreUtils
my
ศัพท์ในขอบเขตนี้ดังนั้นมันก็ดี ที่ถูกกล่าวว่าอาจเป็นชื่อตัวแปรอธิบายเพิ่มเติมสามารถเลือกได้
$::a
และ$::b
จะไม่ได้?
sub uniq { my %seen; grep !$seen{$_}++, @_ }
เป็นการใช้งานที่ดีกว่าเนื่องจากมันสามารถรักษาความสงบเรียบร้อยไว้ได้โดยไม่มีค่าใช้จ่าย หรือดียิ่งขึ้นใช้จากรายการ :: MoreUtils
เอกสารประกอบ Perl มาพร้อมกับชุดคำถามที่พบบ่อย คำถามของคุณถูกถามบ่อย:
% perldoc -q duplicate
คำตอบคัดลอกและวางจากผลลัพธ์ของคำสั่งด้านบนปรากฏด้านล่าง:
พบได้ใน /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod ฉันจะลบองค์ประกอบที่ซ้ำกันออกจากรายการหรืออาร์เรย์ได้อย่างไร (สนับสนุนโดย brian d foy) ใช้แฮช เมื่อคุณคิดว่าคำว่า "ไม่ซ้ำกัน" หรือ "ซ้ำ" ให้คิด "ปุ่มแฮช" หากคุณไม่สนใจคำสั่งขององค์ประกอบคุณก็สามารถทำได้ สร้างแฮชแล้วแตกกุญแจ มันไม่สำคัญสำหรับคุณ สร้างแฮชนั้น: เพียงแค่คุณใช้ "ปุ่ม" เพื่อรับองค์ประกอบที่เป็นเอกลักษณ์ % hash = map {$ _, 1} @array; # หรือแฮชชิ้น: @hash {@array} = (); # หรือ foreach: $ hash {$ _} = 1 foreach (@array); @unique ของฉัน = keys% hash; หากคุณต้องการใช้โมดูลให้ลองใช้ฟังก์ชัน "uniq" "รายชื่อ :: MoreUtils" ในบริบทรายการจะส่งคืนองค์ประกอบที่ไม่ซ้ำกัน รักษาลำดับของพวกเขาในรายการ ในบริบทสเกลาร์จะส่งคืน จำนวนองค์ประกอบที่ไม่ซ้ำกัน ใช้รายการ :: MoreUtils qw (uniq); ฉัน @unique = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 1,2,3,4,5,6,7 $ Unique = uniq ของฉัน (1, 2, 3, 4, 4, 5, 6, 5, 7); # 7 คุณยังสามารถผ่านแต่ละองค์ประกอบและข้ามสิ่งที่คุณเห็น ก่อน. ใช้แฮชเพื่อติดตาม ครั้งแรกที่ลูปเห็น องค์ประกอบองค์ประกอบนั้นไม่มีคีย์ใน% Seen คำสั่ง "ถัดไป" สร้างขึ้น คีย์และใช้ค่าทันทีซึ่งก็คือ "undef" ดังนั้นลูป ทำต่อไปที่ "push" และเพิ่มค่าสำหรับคีย์นั้น ต่อไป เวลาที่ลูปเห็นองค์ประกอบเดียวกันนั้นมีคีย์อยู่ในแฮชและ ค่าสำหรับคีย์นั้นเป็นจริง (เนื่องจากไม่ใช่ 0 หรือ "undef") ดังนั้น ข้ามไปที่การทำซ้ำและวนรอบไปที่องค์ประกอบถัดไป @unique ของฉัน = (); % ของฉันเห็น = (); foreach $ elem ของฉัน (@array) { ถัดไปหากเห็น $ {$ elem} ++; กด @unique, $ elem; } คุณสามารถเขียนสิ่งนี้ได้รวดเร็วยิ่งขึ้นโดยใช้ grep ซึ่งทำเช่นเดียวกัน สิ่ง. % ของฉันเห็น = (); ของฉัน @unique = grep {! $ เห็น {$ _} ++} @array;
รายการติดตั้ง:: MoreUtilsจาก CPAN
จากนั้นในรหัสของคุณ:
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
ควรอยู่ในuniq
สายไม่ใช่@dups
วิธีการทำตามปกติของฉันคือ:
my %unique = ();
foreach my $item (@myarray)
{
$unique{$item} ++;
}
my @myuniquearray = keys %unique;
หากคุณใช้แฮชและเพิ่มรายการลงในแฮช นอกจากนี้คุณยังมีโบนัสในการรู้ว่าแต่ละรายการปรากฏในรายการกี่ครั้ง
ตัวแปร @array เป็นรายการที่มีองค์ประกอบที่ซ้ำกัน
%seen=();
@unique = grep { ! $seen{$_} ++ } @array;
สามารถทำได้ง่าย ๆ ด้วย Perl one liner
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.
บล็อก PFM ทำสิ่งนี้:
ข้อมูลใน @in ถูกป้อนเข้าสู่ MAP MAP สร้างแฮชที่ไม่ระบุชื่อ คีย์ถูกแยกออกจากแฮชและป้อนลงใน @out
อันสุดท้ายนั้นค่อนข้างดี ฉันแค่บิดมันเล็กน้อย:
my @arr;
my @uniqarr;
foreach my $var ( @arr ){
if ( ! grep( /$var/, @uniqarr ) ){
push( @uniqarr, $var );
}
}
ฉันคิดว่านี่น่าจะเป็นวิธีที่อ่านง่ายที่สุด
ลอจิก: แฮชสามารถมีได้เฉพาะคีย์ที่ซ้ำกันดังนั้นวนซ้ำแถวลำดับกำหนดค่าใด ๆ ให้กับแต่ละองค์ประกอบของอาร์เรย์ทำให้องค์ประกอบเป็นกุญแจสำคัญของแฮชนั้น ส่งคืนคีย์ของแฮชซึ่งเป็นอาร์เรย์ที่เป็นเอกลักษณ์ของคุณ
my @unique = keys {map {$_ => 1} @array};
ดีกว่าที่จะทำให้รูทีนย่อยถ้าเราควรจะใช้ฟังก์ชั่นนี้หลายครั้งในรหัสของเรา
sub get_unique {
my %seen;
grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);
List::MoreUtils
use List::MoreUtils qw(uniq);
my @unique = uniq(@array);
คำตอบก่อนหน้านี้สรุปวิธีที่เป็นไปได้ในการทำงานนี้ให้สำเร็จ
แต่ผมขอแนะนำให้ปรับเปลี่ยนสำหรับผู้ที่ใครไม่ดูแลเกี่ยวกับการนับซ้ำกัน แต่ทำดูแลเกี่ยวกับคำสั่ง
my @record = qw( yeah I mean uh right right uh yeah so well right I maybe );
my %record;
print grep !$record{$_} && ++$record{$_}, @record;
โปรดทราบว่าการgrep !$seen{$_}++ ...
เพิ่มขึ้นที่แนะนำก่อนหน้านี้$seen{$_}
ก่อนที่จะปฏิเสธดังนั้นการเพิ่มขึ้นจะเกิดขึ้นไม่ว่าจะได้รับ%seen
หรือไม่ อย่างไรก็ตามข้างต้นวงจรสั้นเมื่อ$record{$_}
เป็นจริงปล่อยให้สิ่งที่เคยได้ยินเมื่อ 'ปิด%record
'
คุณสามารถไปเพื่อความไร้สาระนี้ซึ่งใช้ประโยชน์จากการปรับปรุงอัตโนมัติและการมีปุ่มแฮช:
...
grep !(exists $record{$_} || undef $record{$_}), @record;
อย่างไรก็ตามนั่นอาจนำไปสู่ความสับสน
และหากคุณสนใจที่จะไม่เรียงลำดับหรือนับซ้ำคุณสามารถแฮ็กใหม่โดยใช้แฮชสไลซ์และเคล็ดลับที่ฉันเพิ่งพูดถึง:
...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped
sub uniq{ my %seen; undef @seen{@_}; keys %seen; }
เรียบร้อย
ลองนี้ดูเหมือนว่าฟังก์ชั่น uniq ต้องการรายการที่เรียงลำดับเพื่อให้ทำงานได้อย่างถูกต้อง
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";
ใช้แนวคิดของปุ่มแฮชที่ไม่ซ้ำกัน:
my @array = ("a","b","c","b","a","d","c","a","d");
my %hash = map { $_ => 1 } @array;
my @unique = keys %hash;
print "@unique","\n";
เอาท์พุท: acbd