如何改进这个哈希函数

时间:2013-02-16 20:51:01

标签: r hash

有没有提高这个哈希的初始化速度? 目前,我的机器需要大约20分钟。

#prepare hash()
hash <- list();

mappedV <- # matrix with more than 200,000 elements
for( i in 1:nrow(mappedV) ) {
  hash[[paste(mappedV[i,], collapse = '.')]] <- 0;
}

在这段代码之前,我使用了一个矩阵,但这花了我超过3个小时。所以我不会抱怨20分钟。如果有更好的选择,我只是好奇。我使用哈希函数来计算200,000种可能组合中的每一种。

PS:并发可能是一种选择。但这并没有改善散列。

3 个答案:

答案 0 :(得分:5)

您通常会通过预先分配所需长度的列表来节省大量时间,而不是在每次迭代时增加它。

看哪:

X <- vector(mode="list", 1e5)
Y <- list()

system.time(for(i in 1:1e5) X[[i]] <- 0)
#    user  system elapsed 
#     0.3     0.0     0.3 
system.time(for(i in 1:1e5) Y[[i]] <- 0)
#    user  system elapsed 
#   48.84    0.05   49.34 
identical(X,Y)
# [1] TRUE

因为每次添加时都会复制整个列表Y,所以附加元素只会随着它的大小增加而变得越来越慢。

答案 1 :(得分:4)

你也可以environment作为哈希...让我们看看:

mappedV <- matrix(1:100000, ncol=5)
hash1 <- list()
hash2 <- new.env(hash=TRUE)

system.time(for(i in 1:nrow(mappedV)) hash1[[paste(mappedV[i,], collapse = '.')]] <- 0)
#   user  system elapsed 
# 19.263   1.321  21.634 

system.time(for(i in 1:nrow(mappedV)) hash2[[paste(mappedV[i,], collapse = '.')]] <- 0)
#   user  system elapsed 
#  0.426   0.002   0.430 

更新以回答“需要注意的事项”

正如Josh O'Brien指出的那样,这是如此之快,因为修改后不会复制整个环境。看起来很有用,对吧?

当您希望这些对象的行为与您习惯使用的大多数其他对象的不变性一样时,可能会出现“问题”。在某处修改environment时,它会在任何地方对其进行更改。例如,如果我们将environment传递给一个删除其所有元素的函数,environment将在任何地方被清除,而列表则不会。

证人:

hash1 <- list(a=1:10, b=rnorm(10))
hash2 <- new.env(hash=TRUE)
hash2$a <- 1:10
hash2$b <- rnorm(10)

danger <- function(x, axe) {
  for (wut in axe) x[[wut]] <- NULL
}

## the list is safe
danger(hash1, names(hash1))
hash1
# $a
#  [1]  1  2  3  4  5  6  7  8  9 10
#
# $b
# [1] -0.8575287  0.5248522  0.6957204 -0.7116208
# [2]  0.5536749  0.9860218 -1.2598799 -1.1054205
# [3]  0.3472648

## The environment gets mutilated
danger(hash2, names(hash1))
as.list(hash2)
# $a
# NULL
# 
# $b
# NULL

答案 2 :(得分:2)

它没有使用环境那么快,但是有一个简单的矢量化解决方案来解决这个问题:

mappedV <- matrix(1:100000, ncol = 5)
hashes <- apply(mappedV, 1, paste, collapse = ".")

hash <- list()
hash[hashes] <- 0

当然,您可以将0的向量转换为列表并命名为:

hash <- as.list(rep(0, length = length(hashes)))
names(hash) <- hashes

在我的电脑上显示<0.001s。