【问题标题】:Working with dictionaries/lists to get list of keys使用字典/列表来获取键列表
【发布时间】:2010-05-18 14:10:48
【问题描述】:

我有一个小问题:我在 R 中找不到字典数据结构,所以我改用列表(如 "word"->number)。 那么,如何获取键列表。

【问题讨论】:

    标签: r list hashmap lookup


    【解决方案1】:

    是的,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"
    > 
    

    【讨论】:

    • +1 用于回答问题,而无需提及 OP 的无效方法。
    • 根据列表作为字典代理的预期用途,请谨记,列表的“键”查找是 O(n) 而不是 O(1),这是您对字典(散列键)的期望。
    • 是的,environment 类型用于 R 中,但它不太常见/鲜为人知。
    【解决方案2】:

    如果您的“数字”值都是相同的模式,您甚至不需要列表。如果我以 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
    

    【讨论】:

    • 你如何从这个字典式的 R 结构 foo 中得到 c(12,22,33) 的列表? unlist(lapply(FUN=function(a){foo[[a]]},X = 1:length(foo))) 很不方便。有什么准备好的功能吗?移动问题here
    【解决方案3】:

    为了扩展 Calimo 的一点点答案,我提供了一些在 R 中创建此准词典时您可能会发现有用的东西:

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

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

    b) 检查字典是否包含键:

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

    c) 如何在字典中添加新的键、值对:

    c(foo,tic2=44)

    结果:

    tic       tac       toe     tic2
    12        22        33        44 
    

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

    e) 如何从字典中按键删除对:

    foo

    【讨论】:

    • 我可以添加包含空格的键,比如“奇怪的键”吗?
    • 这样的东西也不起作用c(foo, tic2=NULL)。有什么解决办法吗?
    【解决方案4】:

    首先使用字典的原因是性能。虽然您可以在任务中使用命名向量和列表是正确的,但问题是它们变得非常缓慢并且随着数据的增加而占用大量内存。

    然而很多人不知道的是,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:你为什么不试试看?
    • 使用这种方法代替使用带有名称的列表将我的运行时间从 6 分钟缩短到 1 秒!我理解哈希很好,但是在列表中查找名称时,任何人都可以确认使用了哪种搜索算法?这只是在名称匹配项下遍历列表吗?我想确切地了解为什么列表如此之慢,以及为什么散列对于大量键来说如此之快?
    • @vonjd 我正在尝试在 R 中使用字典并找到了这个实现。但是,当每个值都与一对键相关联时,它是否也有效?提前谢谢你。
    • @shana:你能举例说明你的意思吗?
    【解决方案5】:

    hash 包现已推出: 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"
    

    【讨论】:

    • 如何添加多个值?我试过重复键,但它只存储最后一个值。我也试过分配列表,但它不起作用
    • 字典从不为每个键存储多个值。如果需要,您可以将列表分配给键。
    • 这样的好方法!复制了字典的许多功能和设置,并且非常容易实现。
    【解决方案6】:

    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"
    

    【讨论】:

      【解决方案7】:

      我只是评论一下,当您尝试“伪造”字典时,您也可以从 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)]) 获得相同的结果
      猜你喜欢
      • 2013-08-29
      • 1970-01-01
      • 1970-01-01
      • 2015-01-17
      • 1970-01-01
      • 2020-08-06
      • 2019-10-01
      • 2022-12-01
      相关资源
      最近更新 更多