我在 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
如果您想使用模块,请尝试来自List::MoreUtils
的uniq
函数。
% perldoc -q duplicate
以下是从上述命令输出中复制并粘贴的答案:
如何从列表或数组中删除重复元素?(由 brian d foy 提供)
使用哈希表。当您想到“唯一”或“重复”这些词时,请思考“哈希键”。
如果您不关心元素的顺序,您可以创建哈希表,然后提取键。重要的不是如何创建哈希表,而是使用“keys”获取唯一元素。
my %hash = map { $_, 1 } @array;
# or a hash slice: @hash{ @array } = ();
# or a foreach: $hash{$_} = 1 foreach ( @array );
my @unique = keys %hash;
如果你想使用一个模块,可以尝试使用"List::MoreUtils"中的"uniq"函数。在列表上下文中,它返回唯一的元素,并保留其在列表中的顺序。在标量上下文中,它返回唯一元素的数量。
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
你也可以遍历每个元素并跳过已经看过的元素。使用哈希表进行跟踪。第一次循环遇到一个元素时,在 %Seen 中没有该元素的键。"next" 语句创建了该键,并立即使用其值(即 "undef"),因此循环继续执行 "push" 并增加该键的值。下一次循环遇到相同的元素时,它的键存在于哈希表中,并且该键的值为 true(因为它不是 0 或 "undef"),因此 "next" 跳过该迭代,循环进入下一个元素。
my @unique = ();
my %seen = ();
foreach my $elem ( @array )
{
next if $seen{ $elem }++;
push @unique, $elem;
}
您可以使用grep更简洁地编写此内容,它执行相同的操作。
my %seen = ();
my @unique = grep { ! $seen{ $_ }++ } @array;
从 CPAN 安装 List::MoreUtils
然后在你的代码中使用:
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
中。” - incutonezList::Util
已经有了 uniq
,因此不再需要使用 MoreUtils。 - Sundeep我通常使用的方法是:
my %unique = ();
foreach my $item (@myarray)
{
$unique{$item} ++;
}
my @myuniquearray = keys %unique;
如果您使用哈希表并将项目添加到哈希表中,则还可以知道列表中每个项目出现的次数。
可以用一个简单的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.
PFM块的作用如下:
@in
中的数据被输入到map
中。 map
构建一个匿名哈希表。从哈希表中提取keys
并输入到@out
中。
逻辑:哈希表只能有唯一的键,因此遍历数组,将任何值分配给数组的每个元素,并将元素作为哈希表的键。返回哈希表的键,即为您的唯一数组。
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);
@array
是包含重复元素的列表。%seen=();
@unique = grep { ! $seen{$_} ++ } @array;
那个最后的翻译已经很不错了,我只是想稍微修改一下:
my @arr;
my @uniqarr;
foreach my $var ( @arr ){
if ( ! grep( /$var/, @uniqarr ) ){
push( @uniqarr, $var );
}
}
我认为这可能是最易读的做法。
之前的回答已经总结了可能实现此任务的方式。
然而,我建议对于那些不关心重复计数但关心顺序的人进行修改。
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;
然而,这可能会导致一些混淆。
如果您不关心顺序或重复计数,则可以使用哈希切片和我刚提到的技巧进行另一种hack:
...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped
sub uniq{ my %seen; undef @seen{@_}; keys %seen; }
真是太好了。 - stevesliva试一下这个,看起来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";
sort
使用非局部变量是一个极其糟糕的设计决策。@szabgab - Brian Vandenberg