【问题标题】:how to create a list in R from two vectors (one would be the keys, the other the values)?如何从两个向量(一个是键,另一个是值)在 R 中创建一个列表?
【发布时间】:2017-03-30 14:03:55
【问题描述】:

我有两个向量,我想在 R 中创建一个列表,其中一个向量是键,另一个是值。我以为我会很容易地在我的书中找到答案或在谷歌上搜索,我期待找到一个解决方案,比如将名称添加到向量(names(v)

我自己提出了两种可能的解决方案,但对我来说没有一个是优雅的。 R 不是我的主要编程语言,但我认为 R 如此务实应该存在更好的解决方案(类似于 list(keys=x, values=y))。

我的解决方案1:经典循环解决方案:

    > xx <- 1:3
    > yy <- letters1:3
    > zz =list()
    >for(i in 1:length(yy)) {zz[[yy[i]]]<-xx[i]}

我的解决方案 2:通过命名向量的间接路径:

    > names(xx) <- letters[1:3]
    > as.list(xx)

似乎我有一个解决方案,但我的向量有 100 万个或更多元素,我不仅担心编码风格(对我很重要)而且担心效率(但我不知道如何在 R 中进行分析)。有没有更合适的方法来做到这一点?使用命名向量快捷方式是一种好习惯吗?

[[UPDATE]] 我的应用程序,可能我过度简化了问题以使其可重现。我想为列表的元素命名。我首先尝试了 names() 但似乎我做错了什么并且没有工作。所以我得到了一个错误的想法,即 names() 不适用于列表。但他们确实如接受的答案所示

【问题讨论】:

  • 您说“一百万或更多元素(即大对象)”?你能精确地确定你的对象的结构以了解它有多大吗?
  • @agstudy 我认为这意味着由于元素的数量,OP 将向量描述为大对象,而不是将元素本身描述为大对象?尽管如此,将两个向量组合在一个列表中......

标签: r


【解决方案1】:

如果您的值都是标量,那么拥有一个只是向量的“键值存储”没有任何问题。

vals <- 1:1000000
keys <- paste0("key", 1:1000000)
names(vals) <- keys

然后您可以检索与给定键对应的值

vals["key42"]
[1] 42

IIRC R 将散列用于基于字符的索引,因此无论向量大小如何,查找都应该很快。

如果您的值可以是任意对象,那么您确实需要一个列表。

vals <- list(1:100, lm(speed ~ dist, data=cars), function(x) x^2)
names(vals) <- c("numbers", "model", "function")

sq <- vals[["function"]]
sq(5)
[1] 25

如果您的问题是关于构建列表,我不会太担心。 R 内部是写时复制(对象只有在其内容被修改时才会被复制),所以做类似

vals <- list(1:1000000, 1:1000000, <other big objects>)

实际上不会复制所有内容。

编辑:我刚刚检查过,如果您执行lst &lt;- list(....),R 复制所有内容。去搞清楚。因此,如果您已经接近机器上的内存限制,这将不起作用。另一方面,如果您执行names(lst) &lt;- ....,它不会复制lst。再去看看。

【讨论】:

  • +1 我接受 SimmonO101 上的这个答案只是因为它有点复杂,但基本上两者都是好的答案。正如我在更新的问题中提出的那样,我错误地认为 names() 不能与列表一起使用,因此我试图找到其他选项。谢谢。
【解决方案2】:

可以使用setNames在一个语句中完成:

xx <- 1:3
yy <- letters[1:3]

创建一个命名列表:

as.list(setNames(xx, yy))
# $a
# [1] 1
# 
# $b
# [1] 2
# 
# $c
# [1] 3

或命名向量:

setNames(xx, yy)
# a b c 
# 1 2 3

就列表而言,这在编程上等同于您的“命名向量”方法,但可能更优雅一些。


这里有一些基准测试表明这两种方法的速度一样快。另请注意,操作顺序对于避免不必要且成本高昂的数据副本非常重要:

f1 <- function(xx, yy) {
  names(xx) <- yy
  as.list(xx)
}

f2 <- function(xx, yy) {
  out <- as.list(xx)
  names(out) <- yy
  out
}

f3 <- function(xx, yy) as.list(setNames(xx, yy))
f4 <- function(xx, yy) setNames(as.list(xx), yy)

library(microbenchmark)
microbenchmark(
  f1(xx, yy),
  f2(xx, yy),
  f3(xx, yy),
  f4(xx, yy)
)
# Unit: microseconds
#        expr    min      lq  median      uq     max neval
#  f1(xx, yy) 41.207 42.6390 43.2885 45.7340 114.853   100
#  f2(xx, yy) 39.187 40.3525 41.5330 43.7435 107.130   100
#  f3(xx, yy) 39.280 41.2900 42.1450 43.8085 109.017   100
#  f4(xx, yy) 76.278 78.1340 79.1450 80.7525 180.825   100

【讨论】:

    【解决方案3】:

    这里另一个重要的选择是使用data.table。它使用键对结构进行排序,特别是当您有大量数字时访问元素非常快。这里举个例子:

    library(data.table)   
    DT <- data.table(xx = 1:1e6, 
                 k = paste0("key", 1:1e6),key="k")
    

    Dt 是具有 2 列的 data.table ,我将列 k 设置为键。 DT xxk 1:1键1 2:10键10 3:100键100 4:1000键1000 5:10000键10000 ---
    999996: 999995 密钥999995 999997: 999996 密钥999996 999998: 999997 密钥999997 999999: 999998 密钥999998 1000000: 999999 key999999

    现在我可以使用如下键访问我的 data.table:

    DT['key1000']
             k   xx
    1: key1000 1000
    

    这是一个将 data.table 解决方案与命名向量进行比较的基准测试:

    vals <- 1:1000000
    DT <- data.table(xx = vals ,
                     k = paste0("key", vals),key="k")
    keys <- paste0("key", vals)
    names(vals) <- keys
    library(microbenchmark)
    microbenchmark( vals["key42"],DT["key42"],times=100)
    
    Unit: microseconds
              expr        min          lq     median         uq        max neval
     vals["key42"] 111938.692 113207.4945 114924.010 130010.832 361077.210   100
       DT["key42"]    768.753    797.0085   1055.661   1067.987   2058.985   100
    

    【讨论】:

    • +1 data.table 是这些有用的软件包之一,我一直在附近,但从来没有时间学习它以便在生产中使用它。
    【解决方案4】:

    你的意思是这样做吗?...

    xx <- 1:3
    yy <- letters[1:3]
    zz <- list( xx , yy )
    names(zz) <- c("keys" , "values")
    zz
    #$keys
    #[1] 1 2 3
    
    #$values
    #[1] "a" "b" "c"
    

    AFAIK 这是制作向量列表的规范方法。我很高兴得到纠正。如果您是 R 新手,我建议通常使用for 循环是不明智的,因为通常矢量化方法可以完成大多数 em> 更高效、更快的任务。

    【讨论】:

    • 或多或少(不使用此名称作为名称,而是使用键向量;-))。我希望向量的内容成为列表内容的名称。 Names() 是我尝试的第一件事,但我不记得为什么,它不起作用(可能我做错了什么)并且我错误地认为 names() 仅适用于向量。我知道循环性能,这就是我问的原因,但无论如何感谢您的双重检查。
    【解决方案5】:

    Hong 的输出是错误的。

    应该使用 vals[["key42"]]

    > vals[["key42"]]
    [1] 42
    
    vals <- 1:1000000
    keys <- paste0("key", 1:1000000)
    names(vals) <- keys
    
    vals["key42"]
    key42
       42
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-20
      • 1970-01-01
      • 2011-09-21
      • 2012-11-12
      • 1970-01-01
      • 2020-11-26
      • 2023-04-02
      • 2021-12-06
      相关资源
      最近更新 更多