在R中使用字典/列表


89

我有一个琐碎的问题:我无法在R中找到字典数据结构,所以我改用列表(例如“ word”-> number)。所以,现在我有问题如何获取键列表。有人知道吗

Answers:


118

是的,该list类型是一个很好的近似值。您可以names()在列表上使用以设置和检索“键”:

> foo <- vector(mode="list", length=3)
> names(foo) <- c("tic", "tac", "toe")
> foo[[1]] <- 12; foo[[2]] <- 22; foo[[3]] <- 33
> foo
$tic
[1] 12

$tac
[1] 22

$toe
[1] 33

> names(foo)
[1] "tic" "tac" "toe"
> 

18
+1用于回答问题,但未提及OP的无效方法。
马雷克(Marek)2010年

3
根据列表作为字典代理的预期用途,请谨记,对列表的“关键”查找是O(n)而不是O(1),这是您期望的字典(散列键)。
egnha

4
是的,该environment类型用于R中的类型,但不太常见/鲜为人知。
德克·埃德比布特

56

如果您的“数字”值全部为相同模式,则甚至不需要列表。如果我以Dirk Eddelbuettel的示例为例:

> foo <- c(12, 22, 33)
> names(foo) <- c("tic", "tac", "toe")
> foo
tic tac toe
 12  22  33
> names(foo)
[1] "tic" "tac" "toe"

仅当您的值是混合模式(例如字符和数字)或向量时,才需要列表。

对于列表和向量,单个元素都可以按名称进行子集化:

> foo["tac"]
tac 
 22 

或列表:

> foo[["tac"]]
[1] 22

1
如何获得c(12,22,33)该字典式R结构foo的列表?unlist(lapply(FUN=function(a){foo[[a]]},X = 1:length(foo)))非常不方便。有准备好的功能吗?在此处
嗯,2017年

18

为了扩展Calimo的答案,我介绍了在R中创建此准词典时可能会发现有用的其他内容:

a)如何返回字典的所有值:

>as.numeric(foo)
[1] 12 22 33

b)检查字典的CONTAINS KEY:

>'tic' %in% names(foo)
[1] TRUE

c)如何添加新键,值对到字典:

c(foo,tic2 = 44)

结果:

tic       tac       toe     tic2
12        22        33        44 

d)如何满足REAL DICTIONARY的要求-键不能重复(UNIQUE KEYS)?您需要组合b)和c)并构建函数来验证是否有这样的密钥,然后执行所需的操作:例如,不允许插入,如果新密钥与旧密钥不同,则更新值,或者以某种方式重建密钥(例如加上一些数字,因此它是唯一的)

e)如何从字典中删除密钥对:

foo <-foo [which(foo!= foo [[“ tac”]])]]


我可以添加包含空格的键,例如“奇怪键”吗?
user1700890

同样这样的事情不起作用c(foo, tic2=NULL)。有没有解决的办法?
user1700890

15

首先使用字典的原因是性能。尽管可以为任务使用命名的向量和列表是正确的,但问题是它们变得非常慢,并且内存消耗了更多数据。

但是,许多人不知道的是R 确实具有内置的字典数据结构:具有选项的环境hash = TRUE

请参阅以下示例,了解如何使其工作:

# vectorize assign, get and exists for convenience
assign_hash <- Vectorize(assign, vectorize.args = c("x", "value"))
get_hash <- Vectorize(get, vectorize.args = "x")
exists_hash <- Vectorize(exists, vectorize.args = "x")

# keys and values
key<- c("tic", "tac", "toe")
value <- c(1, 22, 333)

# initialize hash
hash = new.env(hash = TRUE, parent = emptyenv(), size = 100L)
# assign values to keys
assign_hash(key, value, hash)
## tic tac toe 
##   1  22 333
# get values for keys
get_hash(c("toe", "tic"), hash)
## toe tic 
## 333   1
# alternatively:
mget(c("toe", "tic"), hash)
## $toe
## [1] 333
## 
## $tic
## [1] 1
# show all keys
ls(hash)
## [1] "tac" "tic" "toe"
# show all keys with values
get_hash(ls(hash), hash)
## tac tic toe 
##  22   1 333
# remove key-value pairs
rm(list = c("toe", "tic"), envir = hash)
get_hash(ls(hash), hash)
## tac 
##  22
# check if keys are in hash
exists_hash(c("tac", "nothere"), hash)
##     tac nothere 
##    TRUE   FALSE
# for single keys this is also possible:
# show value for single key
hash[["tac"]]
## [1] 22
# create new key-value pair
hash[["test"]] <- 1234
get_hash(ls(hash), hash)
##  tac test 
##   22 1234
# update single value
hash[["test"]] <- 54321
get_hash(ls(hash), hash)
##   tac  test 
##    22 54321

编辑:基于此答案,我写了一篇博客文章,内容涉及更多内容:http : //blog.ephorie.de/hash-me-if-you-can


它对多值关系有用吗?例如tic = 1和tic = 17
skan

@skan:为什么不尝试呢?
vonjd

使用这种方法代替使用带有名称的列表,我的运行时间从6分钟缩短到1秒!我知道哈希很好,但是在列表中查找名称时,谁能确认使用哪种搜索算法?这只是遍历名称匹配项下的列表吗?我想确切地理解为什么列表如此之慢,以及为什么哈希对于大量的键而言如此之快?
菲尔(Phil)

@vonjd我正在尝试在R中使用字典并找到此实现。但是,当每个值都与一对键相关联时,它也起作用吗?先感谢您。
萨维

@shana:您能举个例子说明您的确切意思吗?
vonjd

9

包装 哈希现在可用:https : //cran.r-project.org/web/packages/hash/hash.pdf

例子

h <- hash( keys=letters, values=1:26 )
h <- hash( letters, 1:26 )
h$a
# [1] 1
h$foo <- "bar"
h[ "foo" ]
# <hash> containing 1 key-value pair(s).
#   foo : bar
h[[ "foo" ]]
# [1] "bar"

如何添加多个值?我试过重复键,但它只存储最后一个值。我也尝试过分配列表,但没有用
skan,skan,2017年

字典永远不会为每个键存储多个值。您可以根据需要分配一个键列表。
BallpointBen

7

Dirk答案的简短变化:

# Create a Color Palette Dictionary 
> color <- c('navy.blue', 'gold', 'dark.gray')
> hex <- c('#336A91', '#F3C117', '#7F7F7F')

> # Create List
> color_palette <- as.list(hex)
> # Name List Items
> names(color_palette) <- color
> 
> color_palette
$navy.blue
[1] "#336A91"

$gold
[1] "#F3C117"

$dark.gray
[1] "#7F7F7F"

4

我只是评论说,table当您尝试“伪造”字典时,您也可以从中受益匪浅,例如

> x <- c("a","a","b","b","b","c")
> (t <- table(x))
x
a b c 
2 3 1 
> names(t)
[1] "a" "b" "c"
> o <- order(as.numeric(t))
> names(t[o])
[1] "c" "a" "b"

等等


我认为as.numeric()没有必要。该表已经是数字。您可以通过names(t[order(t)])
Rich Scriven
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.