如何从 Perl 中的数组中删除重复项?

Posted

技术标签:

【中文标题】如何从 Perl 中的数组中删除重复项?【英文标题】:How do I remove duplicate items from an array in Perl? 【发布时间】:2010-09-05 16:17:08 【问题描述】:

我在 Perl 中有一个数组:

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

如何从数组中删除重复项?

【问题讨论】:

【参考方案1】:

您可以像 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 函数

【讨论】:

请不要在示例中使用 $a 或 $b,因为它们是 sort() 的神奇全局变量 这是一个my 在这个范围内的词法,所以没关系。话虽如此,可能会选择一个更具描述性的变量名称。 @ephemient 是的,但是如果您要在此函数中添加排序,那么它将胜过 $::a$::b,不是吗? @BrianVandenberg 欢迎来到 1987 年的世界——当它被创建时——以及几乎 100% 的 perl 后缀兼容性——所以它无法被消除。 sub uniq my %seen; grep !$seen$_++, @_ 是一个更好的实现,因为它可以免费保留订单。或者更好的是,使用 List::MoreUtils 中的那个。【参考方案2】:

Perl 文档附带了一组很好的常见问题解答。您的问题经常被问到:

% perldoc -q duplicate

从上面命令的输出中复制和粘贴的答案如下所示:


在 /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod 中找到

如何从列表或数组中删除重复元素? (由布赖恩·d·福伊提供)

使用哈希。当你认为“独特”或“重复”这些词时,想想 “哈希键”。

如果您不关心元素的顺序,您可以创建哈希然后提取键。如何创建散列并不重要:只是使用“键”来获取唯一元素。

   my %hash   = map  $_, 1  @array;
   # or a hash slice: @hash @array  = ();
   # or a foreach: $hash$_ = 1 foreach ( @array );

   my @unique = keys %hash;

如果您想使用模块,请尝试从 “列表::MoreUtils”。在列表上下文中,它返回唯一元素,保留它们在列表中的顺序。在标量上下文中,它返回唯一元素的数量。

   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 中没有键。 “下一个”语句创建 键并立即使用其值,即“undef”,因此循环 继续“推送”并增加该键的值。下一个 当循环看到相同的元素时,它的键存在于哈希中,并且 该键的值为真(因为它不是 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;

【讨论】:

perldoc.perl.org/… John iz in mah anzers 偷了 mah rep! 我认为您应该通过实际查找问题获得奖励积分。 我喜欢最好的答案是 95% 的复制粘贴和 3 句 OC。明确地说,这最好的答案;我只是觉得这个事实很有趣。【参考方案3】:

从 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);

【讨论】:

List::MoreUtils 没有与 perl 捆绑的事实有点损害使用它的项目的可移植性:((我不会) @Ranguard:@dup_list 应该在uniq 调用中,而不是@dups @yassinphilip CPAN 是使 Perl 尽可能强大和出色的原因之一。如果您仅基于核心模块编写项目,那么您将极大地限制您的代码,以及可能大量编写的代码,这些代码试图做一些模块做得更好的事情,只是为了避免使用它们。此外,使用核心模块并不能保证任何事情,因为不同的 Perl 版本可以在发行版中添加或删除核心模块,因此可移植性仍然取决于此。 Perl v5.26.0 以上,List::Utiluniq,所以不需要 MoreUtils【参考方案4】:

我通常的做法是:

my %unique = ();
foreach my $item (@myarray)

    $unique$item ++;

my @myuniquearray = keys %unique;

如果您使用哈希并将项目添加到哈希中。您还可以知道每个项目在列表中出现了多少次。

【讨论】:

如果您需要,这样做的缺点是不保留原始订单。 最好使用slices而不是foreach循环:@unique@myarray=()【参考方案5】:

可以用一个简单的 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 中的数据被输入mapmap 构建一个匿名哈希。从哈希中提取keys 并输入@out

【讨论】:

【参考方案6】:

方法一:使用哈希

逻辑:哈希只能有唯一的键,因此遍历数组,为数组的每个元素分配任何值,保持元素作为该哈希的键。哈希的返回键,它是你唯一的数组。

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

方法 2:方法 1 的扩展以实现可重用性

如果我们应该在代码中多次使用此功能,最好创建一个子例程。

sub get_unique 
    my %seen;
    grep !$seen$_++, @_;

my @unique = get_unique(@array);

方法三:使用模块List::MoreUtils

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

【讨论】:

【参考方案7】:

变量@array是有重复元素的列表

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

【讨论】:

【参考方案8】:

最后一张还不错。我只是稍微调整一下:

my @arr;
my @uniqarr;

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

我认为这可能是最易读的方式。

【讨论】:

【参考方案9】:

以前的答案几乎总结了完成此任务的可能方法。

但是,对于那些关心计算重复但确实关心顺序的人,我建议进行修改。 p>

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; Neat.【参考方案10】:

试试这个,好像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";

【讨论】:

【参考方案11】:

使用唯一哈希键的概念:

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

输出: a c b d

【讨论】:

以上是关于如何从 Perl 中的数组中删除重复项?的主要内容,如果未能解决你的问题,请参考以下文章

从 Kotlin 中的数组中删除重复项

如何从二维数组中删除重复项? [关闭]

如何从 C# 数组中删除重复项?

从 BigQuery 中的数组中删除重复项

如何从 Javascript 中的数组中删除重复项?

如何使用两个键删除数组中的重复项?