我需要查看字符串数组中是否有重复项,这是最省时的方法吗?
答案 0 :(得分:27)
我喜欢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' is duplicated.
'no' is duplicated.
答案 1 :(得分:23)
将数组转换为哈希是最快的方法[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)
(当所有内容都重复时),但是如果您的阵列很大并且没有太多重复项,那么您将获胜。
除了理论之外,基准测试显示后者开始在大型阵列(如超过一百万)上丢失,并且重复次数很高。
答案 2 :(得分:7)
如果您还需要无需数组的数组,最快使用经过大量优化的库List::MoreUtils,然后将结果与原始数据进行比较:
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}++;
}
答案 3 :(得分:6)
创建哈希或集合或使用 collections.Counter() 。
当您遇到每个字符串/输入检查以查看哈希中是否存在该实例时。如果是这样,它就是重复的(做你想做的任何事情)。否则,使用字符串作为键,将值(例如,哦,比如数字1)添加到哈希值。
示例(使用Python collections.Counter):
#!python
import collections
counts = collections.Counter(mylist)
uniq = [i for i,c in counts.iteritems() if c==1]
dupes = [i for i, c in counts.iteritems() if c>1]
这些计数器是围绕字典构建的(用于散列映射集合的Pythons名称)。
这是时间有效的,因为散列键被索引。在大多数情况下,键的查找和插入时间是在接近恒定的时间内完成的。 (事实上,Perl“哈希”是所谓的,因为它们是使用一种称为“哈希”的算法技巧实现的 - 一种校验和选择,因为它在输入任意输入时具有极低的冲突概率。)
如果将值初始化为整数,从1开始,则可以在散列中找到其键时递增每个值。这是计算字符串的最有效的通用方法。
答案 4 :(得分:2)
不是直接答案,但这将返回没有重复的数组:
#!/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";
答案 5 :(得分:1)
除非您有一些特定的要求,否则请不要问最有效的方法,例如“我必须在一秒钟内重复删除100,000个整数列表”。否则,你会担心没事的会花多长时间。
答案 6 :(得分:1)
类似于@ Schwern的第二个解决方案,但是在sort
的比较函数中稍早检查重复项:
use strict;
use warnings;
@_ = sort { print "dup = $a$/" if $a eq $b; $a cmp $b } @ARGV;
它不会像散列解决方案一样快,但它需要更少的内存并且非常可爱