用于双向密钥< - > val查找表的适当数据结构

时间:2012-10-08 00:09:03

标签: r data-structures

我有一组键(字符)< - > R中的哈希(整数)关联。我想将这些关联存储在一个结构中,该结构允许我按键引用键/哈希对,也可以通过哈希引用。

类似

"hello" <-> 1234
变量db中的

并使用(ish;不一定是这种确切的访问语法)访问它:

db["hello"] -> 1234
db[1234] -> "hello"

我尝试使用数据框,并将密钥命名为rownames。但后来我无法通过哈希整数引用一行。如果我使用哈希整数作为rownames,那么我不能通过keyname等引用

我目前的解决方案是将两个dbs保持为两个数据帧。一个有哈希作为rownames,另一个有键作为rownames。这是有效的,但保持两个相同的数据帧(除了他们的rownames)似乎有点尴尬和重复。

我希望它在两个方向都超级快:)。我认为这意味着字符方向为O(log(n)),整数方向为O(1),但我不是数据结构/算法专家。整数方向的O(log(n))可能是正常的,但我认为O(n)(需要遍历整个数据库解决方案)在任何一个方向都会对事情造成太大的影响。

db也是双射的。也就是说,每个键只映射一个值,每个值只映射一个键。

编辑:感谢迄今为止的帖子:

运行一些测试,匹配技术肯定比键控data.table慢。正如Martin所指出的,这仅仅是因为匹配创建键控表所需的时间。也就是说,匹配和键控data.table都执行二进制搜索以查找值。但无论如何,在返回单个值时,匹配对于我的需求来说太慢了。所以我将编写一个data.table解决方案并发布。

> system.time(match(1,x))
   user  system elapsed 
  0.742   0.054   0.792 
> system.time(match(1,x))
   user  system elapsed 
  0.748   0.064   0.806 
> system.time(match(1e7,x))
   user  system elapsed 
  0.747   0.067   0.808 
> system.time(x.table[1])
   user  system elapsed 
      0       0       0 
> system.time(x.table[1e7])
   user  system elapsed 
  0.001   0.001   0.000 
> system.time(x.table[1e7])
   user  system elapsed 
  0.005   0.000   0.005 
> system.time(x.table[1])
   user  system elapsed 
  0.001   0.000   0.000 
> system.time(x.table[1])
   user  system elapsed 
  0.020   0.001   0.038 

EDIT2:

我选择了fmatch解决方案和一个命名向量。我喜欢匹配方法的简单性,但我正在对数据库进行重复查找,因此在每次调用匹配时重新创建哈希表的性能太高了。

fmatch具有与match相同的接口,适用于相同的命名向量数据类型等。它只是缓存/ memoizes创建的哈希表,因此对命名向量的后续调用只需执行哈希查找。所有这些都是从调用者中抽象出来的,所以fmatch只是一个匹配的dropin。

双向查找的简单包装代码:

getChunkHashes = function(chunks, db) {
        return(db[fmatch(chunks, names(db))])
}

getChunks = function(chunkHashes, db) {
        return(names(db[fmatch(chunkHashes, db)]))
}

3 个答案:

答案 0 :(得分:4)

基本方法是使用命名向量:

db <- c(hello = 1234, hi = 123, hey = 321)

要从键(s)转到值(s),请使用[

db[c("hello", "hey")]
# hello   hey 
#  1234   321

从值(s)转到键(s)有点棘手:

names(db)[match(c(321, 123), db)]
# [1] "hey" "hi"

(请注意,match(x, y)会返回xy第一个匹配的索引,因此这种方法只有在您的地图是单射的情况下才有效你在问题中没有说清楚的事情。)

如果您发现上一次使用有点过于“沉重”,那么您绝对可以编写自己的功能。

注意:正如所指出的,这种方法在值到关键方向上可能很慢,因此对于大型地图的重复双向访问可能并不理想。为了防御它,它易于实现,不需要base以外的任何包,并且将为99%的人的需求做一个非常体面的工作。如果没有,它可以在这里用作反对更快替代品的基准。

答案 1 :(得分:3)

鉴于:

  

db也是双射的。也就是说,每个键只映射一个值,每个值只映射一个键。

然后我会建议哈希解决方案(例如hash package),fastmatch packagedata.table::chmatchdata.table中的键控连接更适用于有序多列键和/或分组数据,这实际上不是您的问题。

答案 2 :(得分:2)

更多关于@claytonstanley对@flodel的回应的关注。 match对其中一个参数进行哈希,然后搜索另一个。成本是创建哈希而不是查找

> n = 1e7; x = seq_len(n)
> system.time(match(1, x))
   user  system elapsed 
  1.156   0.064   1.222 
> system.time(match(n, x))
   user  system elapsed 
  1.152   0.068   1.221 

并且对所执行的查找次数进行摊销

> y = sample(x)
> system.time(match(y, x))
   user  system elapsed 
  2.112   0.052   2.167 

所以你肯定希望查找“矢量化”。