在使用R之前,我使用了相当多的Perl。在Perl中,我经常使用散列,并且在Perl中查找散列通常被认为是快速的。
例如,以下代码将填充最多10000个键/值对的散列,其中键是随机字母,值是随机整数。然后,它在该哈希中执行10000次随机查找。
#!/usr/bin/perl -w
use strict;
my @letters = ('a'..'z');
print @letters . "\n";
my %testHash;
for(my $i = 0; $i < 10000; $i++) {
my $r1 = int(rand(26));
my $r2 = int(rand(26));
my $r3 = int(rand(26));
my $key = $letters[$r1] . $letters[$r2] . $letters[$r3];
my $value = int(rand(1000));
$testHash{$key} = $value;
}
my @keyArray = keys(%testHash);
my $keyLen = scalar @keyArray;
for(my $j = 0; $j < 10000; $j++) {
my $key = $keyArray[int(rand($keyLen))];
my $lookupValue = $testHash{$key};
print "key " . $key . " Lookup $lookupValue \n";
}
现在越来越多,我想在R中有一个类似哈希的数据结构。以下是等效的R代码:
testHash <- list()
for(i in 1:10000) {
key.tmp = paste(letters[floor(26*runif(3))],sep="")
key <- capture.output(cat(key.tmp,sep=""))
value <- floor(1000*runif(1))
testHash[[key]] <- value
}
keyArray <- attributes(testHash)$names
keyLen = length(keyArray);
for(j in 1:10000) {
key <- keyArray[floor(keyLen*runif(1))]
lookupValue = testHash[[key]]
print(paste("key",key,"Lookup",lookupValue))
}
代码似乎在做同等的事情。然而,Perl一个快得多:
>time ./perlHashTest.pl real 0m4.346s user **0m0.110s** sys 0m0.100s
与R比较:
time R CMD BATCH RHashTest.R real 0m8.210s user **0m7.630s** sys 0m0.200s
什么解释了差异?在R列表查找只是不好吗?
增加到100,000列表长度和100,000次查找只夸大了差异?是否有更好的替代R的哈希数据结构比本机list()?
解决方法
基本原因是具有命名元素的R列表不进行哈希。哈希查找是O(1),因为在插入过程中,使用散列函数将密钥转换为整数,然后将值放在空间的hash(key)%num_spots数组num_spots long(这是一个大的简化,避免处理冲突的复杂性)。查找键只需要哈希键来找到值的位置(这是O(1),与O(n)数组查找)。 R列表使用名称查找,它们是O(n)。
正如Dirk所说,使用哈希包。这是一个巨大的限制是,它使用环境(哈希)和覆盖的方法来模仿哈希表。但是一个环境不能包含另一个环境,所以你不能使用哈希函数嵌套哈希。
一开始我在C / R中实现了一个可以嵌套的纯哈希表数据结构,但是在我处理其他事情时,它继续我的项目。这将是很高兴有虽然:-)