Arrays 什么';使用Perl检查数据数组中重复项的最有效方法是什么?
我需要查看字符串数组中是否存在重复项,最节省时间的方法是什么?不是直接答案,但这将返回一个没有重复项的数组:Arrays 什么';使用Perl检查数据数组中重复项的最有效方法是什么?,arrays,perl,Arrays,Perl,我需要查看字符串数组中是否存在重复项,最节省时间的方法是什么?不是直接答案,但这将返回一个没有重复项的数组: #!/usr/bin/perl use strict; use warnings; my @arr = ('a','a','a','b','b','c'); my %count; my @arr_no_dups = grep { !$count{$_}++ } @arr; print @arr_no_dups, "\n"; 创建散列或集合,或使用 当您遇到每个字符串/输入时,请检
#!/usr/bin/perl
use strict;
use warnings;
my @arr = ('a','a','a','b','b','c');
my %count;
my @arr_no_dups = grep { !$count{$_}++ } @arr;
print @arr_no_dups, "\n";
创建散列或集合,或使用 当您遇到每个字符串/输入时,请检查散列中是否有该字符串/输入的实例。如果是这样,它就是一个复制品(你想怎么做就怎么做)。否则,使用字符串作为键向散列中添加一个值(例如,哦,比如,数字1) 示例(使用Python collections.Counter): 这些计数器是围绕字典(散列映射集合的Pythons名称)构建的 这是非常省时的,因为哈希键是索引的。在大多数情况下,键的查找和插入时间是在接近恒定的时间内完成的。(事实上,Perl“hash”之所以被称为“hash”,是因为它们是使用一种称为“hashing”的算法技巧实现的——这是一种校验和,当输入任意输入时,它的冲突概率极低)
如果将值初始化为整数(从1开始),则可以在哈希中找到每个值的键时对其进行递增。这几乎是计算字符串的最有效的通用方法。我喜欢Perl的一个地方是它几乎可以像英语一样阅读。这有点道理
use strict;
use warnings;
my @array = qw/yes no maybe true false false perhaps no/;
my %seen;
foreach my $string (@array) {
next unless $seen{$string}++;
print "'$string' is duplicated.\n";
}
输出
“false”重复。
“no”重复。
将数组转换为哈希是最快的方法[
O(n)
],尽管它的内存效率很低。使用for循环比grep快一点,但我不知道为什么
#!/usr/bin/perl
use strict;
use warnings;
my %count;
my %dups;
for(@array) {
$dups{$_}++ if $count{$_}++;
}
一种内存有效的方法是对数组进行适当排序,并遍历数组以查找相等和相邻的条目
# not exactly sort in place, but Perl does a decent job optimizing it
@array = sort @array;
my $last;
my %dups;
for my $entry (@array) {
$dups{$entry}++ if defined $last and $entry eq $last;
$last = $entry;
}
由于排序的原因,这是nlogn
速度,但只需要在%count
中存储重复的数据,而不是第二个数据副本。最坏情况下的内存使用率仍然是O(n)
(当所有内容都被复制时),但是如果您的阵列很大,并且没有太多的重复项,那么您将获胜
撇开理论不谈,基准测试表明,后者在复制率较高的大型阵列(如超过100万个)上开始出现损失。如果您仍然需要未经配置的阵列,则使用高度优化的库是最快的,然后将结果与原始结果进行比较:
use strict;
use warnings;
use List::MoreUtils 'uniq';
my @array = qw(1 1 2 3 fibonacci!);
my @array_uniq = uniq @array;
print ((scalar(@array) == scalar(@array_uniq)) ? "no dupes" : "dupes") . " found!\n";
或者,如果列表很大,并且您希望在找到重复条目后立即退出,请使用哈希:
my %uniq_elements;
foreach my $element (@array)
{
die "dupe found!" if $uniq_elements{$element}++;
}
除非您有一些特定的要求,例如“我必须在不到一秒钟的时间内删除100000个整数的列表”,否则请不要询问做某事最省时的方法。否则,您会担心做某事无缘无故需要多长时间。类似于@Schwern的第二个解决方案,但要在稍早一点的时候从
sort
的比较函数中检查重复项:
use strict;
use warnings;
@_ = sort { print "dup = $a$/" if $a eq $b; $a cmp $b } @ARGV;
它不会像散列解决方案那样快,但它需要更少的内存,而且非常可爱感谢您的全面回答!我现在是用后一种方式做的,但内存不是问题,只是时间,所以我肯定要将它作为哈希重新实现。
my$duppes\u found=!!grep{$\ 1}值%count而更有效的测试是使用grep而不是grep
。实际上甚至my$duppes\u found=@arr==@arr\u no\u duppes代码>应该可以工作。也许OP只是好奇(尽管我同意,除非它被证明是一个瓶颈,否则不值得担心)。无论如何,这应该是对这个问题的评论,而不是回答。
use strict;
use warnings;
@_ = sort { print "dup = $a$/" if $a eq $b; $a cmp $b } @ARGV;