Câu trả lời:
Bạn có thể làm một cái gì đó như thế này như được thể hiện trong perlfaq4 :
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @array = qw(one two three two three);
my @filtered = uniq(@array);
print "@filtered\n";
Đầu ra:
one two three
Nếu bạn muốn sử dụng một mô-đun, hãy thử uniq
chức năng từList::MoreUtils
my
từ vựng trong phạm vi này, vì vậy nó ổn. Điều đó đang được nói, có thể một tên biến mô tả nhiều hơn có thể được chọn.
$::a
và $::b
, đúng không?
sub uniq { my %seen; grep !$seen{$_}++, @_ }
là một thực hiện tốt hơn vì nó bảo tồn trật tự miễn phí. Hoặc thậm chí tốt hơn, sử dụng một từ Danh sách :: MoreUtils.
Tài liệu Perl đi kèm với một bộ Câu hỏi thường gặp. Câu hỏi của bạn thường được hỏi:
% perldoc -q duplicate
Câu trả lời, sao chép và dán từ đầu ra của lệnh trên, xuất hiện bên dưới:
Tìm thấy trong /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod Làm cách nào để xóa các phần tử trùng lặp khỏi danh sách hoặc mảng? (đóng góp bởi brian d foy) Sử dụng một hàm băm. Khi bạn nghĩ các từ "độc nhất" hoặc "trùng lặp", hãy nghĩ "Khóa băm". Nếu bạn không quan tâm đến thứ tự của các yếu tố, bạn có thể tạo hàm băm sau đó giải nén các phím. Nó không quan trọng như thế nào bạn tạo hàm băm đó: chỉ cần bạn sử dụng "khóa" để lấy các phần tử duy nhất. % hash = map {$ _, 1} @array; # hoặc một lát băm: @hash {@array} = (); # hoặc một foreach: $ hash {$ _} = 1 foreach (@array); @unique của tôi = khóa% băm; Nếu bạn muốn sử dụng một mô-đun, hãy thử chức năng "uniq" từ "Danh sách :: MoreUtils". Trong ngữ cảnh danh sách, nó trả về các phần tử duy nhất, giữ gìn trật tự của họ trong danh sách Trong bối cảnh vô hướng, nó trả về số lượng các yếu tố duy nhất. sử dụng Danh sách :: MoreUtils qw (uniq); @unique của tôi = 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 Bạn cũng có thể đi qua từng yếu tố và bỏ qua những yếu tố bạn đã thấy trước. Sử dụng một hàm băm để theo dõi. Lần đầu tiên vòng lặp nhìn thấy một phần tử, phần tử đó không có khóa trong% Seen. Câu lệnh "tiếp theo" tạo ra khóa và ngay lập tức sử dụng giá trị của nó, đó là "undef", do đó, vòng lặp tiếp tục "đẩy" và tăng giá trị cho khóa đó. Tiếp theo Thời gian vòng lặp nhìn thấy cùng một phần tử, khóa của nó tồn tại trong hàm băm và giá trị của khóa đó là đúng (vì nó không phải là 0 hoặc "undef"), vì vậy bỏ qua lần lặp đó và vòng lặp đi đến phần tử tiếp theo. @unique của tôi = (); % tôi thấy = (); quy định $ elem của tôi (@array) { tiếp theo nếu $ thấy {$ elem} ++; đẩy @unique, $ elem; } Bạn có thể viết ngắn gọn hơn bằng cách sử dụng grep, thao tác này cũng tương tự Điều. % tôi thấy = (); @unique của tôi = grep {! $ thấy {$ _} ++} @array;
Danh sách cài đặt :: MoreUtils từ CPAN
Sau đó, trong mã của bạn:
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
nên ở trong uniq
cuộc gọi, không@dups
Cách thông thường của tôi để làm điều này là:
my %unique = ();
foreach my $item (@myarray)
{
$unique{$item} ++;
}
my @myuniquearray = keys %unique;
Nếu bạn sử dụng hàm băm và thêm các mục vào hàm băm. Bạn cũng có phần thưởng khi biết số lần mỗi mục xuất hiện trong danh sách.
Có thể được thực hiện với một lớp lót Perl đơn giản.
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.
Khối PFM thực hiện điều này:
Dữ liệu trong @in được đưa vào MAP. MAP xây dựng một hàm băm ẩn danh. Các khóa được trích xuất từ hàm băm và đưa vào @out
Đó là cuối cùng là khá tốt. Tôi chỉ cần chỉnh nó một chút:
my @arr;
my @uniqarr;
foreach my $var ( @arr ){
if ( ! grep( /$var/, @uniqarr ) ){
push( @uniqarr, $var );
}
}
Tôi nghĩ rằng đây có lẽ là cách dễ đọc nhất để làm điều đó.
Logic: Một hàm băm chỉ có thể có các khóa duy nhất, do đó lặp qua mảng, gán bất kỳ giá trị nào cho từng phần tử của mảng, giữ phần tử làm khóa của hàm băm đó. Trả về các khóa của hàm băm, mảng duy nhất của bạn.
my @unique = keys {map {$_ => 1} @array};
Tốt hơn là tạo một chương trình con nếu chúng ta phải sử dụng chức năng này nhiều lần trong mã của chúng tôi.
sub get_unique {
my %seen;
grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);
List::MoreUtils
use List::MoreUtils qw(uniq);
my @unique = uniq(@array);
Các câu trả lời trước khá nhiều tóm tắt các cách có thể để hoàn thành nhiệm vụ này.
Tuy nhiên, tôi đề nghị sửa đổi đối với những người không quan tâm đến đếm các bản sao, nhưng làm chăm sóc về trật tự.
my @record = qw( yeah I mean uh right right uh yeah so well right I maybe );
my %record;
print grep !$record{$_} && ++$record{$_}, @record;
Lưu ý rằng các grep !$seen{$_}++ ...
mức tăng được đề xuất trước đó $seen{$_}
trước khi phủ định, do đó, mức tăng xảy ra bất kể nó đã được %seen
hay chưa. Tuy nhiên, ở trên, ngắn mạch khi $record{$_}
là đúng, để lại những gì đã nghe một lần 'tắt %record
'.
Bạn cũng có thể đi vì sự lố bịch này, lợi dụng tự động hóa và sự tồn tại của các khóa băm:
...
grep !(exists $record{$_} || undef $record{$_}), @record;
Điều đó, tuy nhiên, có thể dẫn đến một số nhầm lẫn.
Và nếu bạn quan tâm đến việc không đặt hàng hoặc đếm trùng lặp, bạn có thể cho một vụ hack khác bằng cách sử dụng các lát băm và mẹo tôi vừa đề cập:
...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped
sub uniq{ my %seen; undef @seen{@_}; keys %seen; }
Neat.
Hãy thử điều này, có vẻ như hàm uniq cần một danh sách được sắp xếp để hoạt động đúng.
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";
Sử dụng khái niệm khóa băm duy nhất:
my @array = ("a","b","c","b","a","d","c","a","d");
my %hash = map { $_ => 1 } @array;
my @unique = keys %hash;
print "@unique","\n";
Đầu ra: acbd