我有两个向量,我想在R中创建一个列表,其中一个向量是键,另一个是值.我以为我会在我的书中轻松找到答案或googleing并且我期待找到一个解决方案,比如在向量中添加名称(名称(v)< - names_vector),但我失败了.
我有两种可能的解决方案,但对我来说似乎都不优雅.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]}
Run Code Online (Sandbox Code Playgroud)
我的解决方案2:通过命名向量的间接路径:
> names(xx) <- letters[1:3]
> as.list(xx)
Run Code Online (Sandbox Code Playgroud)
似乎我有一个解决方案,但我的矢量有100万或更多的元素,我不仅担心编码风格(对我很重要)而且还担心效率(但我不知道如何在R中进行分析).有没有更合适的方法呢?使用指定的矢量快捷方式是一个好习惯吗?
[[更新]]我的applogies,可能我过于简化了问题,使其可重现.我想给列表的元素命名.我首先尝试了names(),但似乎我做错了什么并且没有用.所以我错误地认为names()不适用于列表.但他们确实如接受的答案所示
Hon*_*Ooi 17
如果你的值都是标量,那么拥有一个只是一个向量的"键值存储"就没有错.
vals <- 1:1000000
keys <- paste0("key", 1:1000000)
names(vals) <- keys
Run Code Online (Sandbox Code Playgroud)
然后,您可以检索与给定键对应的值
vals["key42"]
[1] 42
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
如果你的问题是关于构建列表,我不会太担心.R内部是写时复制(只有在修改了内容时才复制对象),所以做了类似的事情
vals <- list(1:1000000, 1:1000000, <other big objects>)
Run Code Online (Sandbox Code Playgroud)
实际上不会制作一切的额外副本.
编辑:我刚检查过,如果你这样做,R 会复制一切lst <- list(....).去搞清楚.因此,如果您已经接近计算机的内存限制,则无法使用.另一方面,如果你这样做names(lst) <- ....,它将不再制作另一份副本lst.再来一次.
flo*_*del 14
它可以在一个语句中使用setNames:
xx <- 1:3
yy <- letters[1:3]
Run Code Online (Sandbox Code Playgroud)
要创建命名列表:
as.list(setNames(xx, yy))
# $a
# [1] 1
#
# $b
# [1] 2
#
# $c
# [1] 3
Run Code Online (Sandbox Code Playgroud)
或者命名向量:
setNames(xx, yy)
# a b c
# 1 2 3
Run Code Online (Sandbox Code Playgroud)
在列表的情况下,这在程序上等同于您的"命名向量"方法,但可能更优雅.
以下是一些基准测试,表明这两种方法同样快.另请注意,操作顺序对于避免不必要且昂贵的数据副本非常重要:
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
Run Code Online (Sandbox Code Playgroud)
这里的另一个严肃的选择是使用data.table。使用键对结构进行排序,特别是在有大量元素的情况下,访问元素的速度非常快。这里是一个例子:
library(data.table)
DT <- data.table(xx = 1:1e6,
k = paste0("key", 1:1e6),key="k")
Run Code Online (Sandbox Code Playgroud)
Dt是具有2列的data.table,其中我将k列设置为键。DT xx k 1:1键1 2:10键10 3:100键100 4:1000键1000 5:10000键10000 ---
999996:999995 key999995 999997:999996 key999996 999998:999997 key999997 999999:999998 key999998 1000000:999999 key999999
现在,我可以使用如下键访问data.table:
DT['key1000']
k xx
1: key1000 1000
Run Code Online (Sandbox Code Playgroud)
这里是将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
Run Code Online (Sandbox Code Playgroud)