R 中的列表元素命名

问题描述 投票:0回答:2

我最近一直在处理一些大型、复杂的列表,我看到了一些令人惊讶的行为(至少对我来说),主要与为列表分配名称有关。一个简单的例子:

Fil <- list(
a = list(A=seq(1, 5, 1), B=rnorm(5), C=runif(5)), 
b = list(A="Cat", B=c("Dog", "Bird"), C=list("Squirrel", "Cheetah", "Lion")),
c = list(A=rep(TRUE, 5), B=rep(FALSE, 5), C=rep(NA, 5)))

filList <- list()

for(i in 1:3){
  filList[i] <- Fil[i]
  names(filList)[i] <- names(Fil[i])
}
identical(Fil,filList)
[1] TRUE

但是:

for(i in 1:3){
  filList[i] <- Fil[i]
  names(filList[i]) <- names(Fil[i])
}
identical(Fil,filList)
[1] FALSE

我认为它让我感到困惑的主要原因是因为第一个 for 循环中第一个

names
行的左侧形式需要与右侧的形式不同才能工作;我本以为这些应该是一样的。有人可以向我解释一下吗?

r list names
2个回答
62
投票

第一种情况是正确的用法。在第二种情况下,您将

filList[i]
发送到
names<-
,它仅作为临时子集对象存在。

或者,您可以在循环之外执行所有操作:

names(filList) <- names(Fil)

0
投票

正如@James指出的,

names(filList)[i] <- ...
是正确的方法,而
names(filList[i]) <- ...
不起作用。

来自

?names

可以通过一般规则仅更新部分名称属性:

names(z)[3] <- "c2"
。这是有效的,因为那里的表达式被计算为
z <- "names<-"(z, "[<-"(names(z), 3, "c3"))

z <- list(a = 1, b = "c", c = 1:3)
names(z)[3] <- "c2"
z
#> $a
#> [1] 1
#> 
#> $b
#> [1] "c"
#> 
#> $c2
#> [1] 1 2 3

z <- "names<-"(z, "[<-"(names(z), 3, "c3"))
z
#> $a
#> [1] 1
#> 
#> $b
#> [1] "c"
#> 
#> $c3
#> [1] 1 2 3

但是,您的第二种方法(

names(filList[i]) <- 
)不起作用的原因不是“您创建了一个未绑定的临时变量,您可以更改其名称,但它永远不重要,因为它只是一个临时变量”,而是默认的子设置赋值运算符
[<-
不会转移名称(这是有道理的,因为
names
是整个
attributes
SEXPREC
而不是单个元素)。在 R 中,
f(x[i])<- ...
不一定与
tmp <- x[i]; f(tmp) <- ...
相同!一般来说,虽然 R 鼓励函数式编程,但 R 函数(如
`<-`
)可以对调用环境做任何他们想做的事情,并且不是通过引用或值而是作为表达式接收参数。

我们可以重写子集分配运算符以使其也分配名称:

z <- list(a = 1, b = "c", c = 1:3)

names(z[2]) <- "b2" # does not work
z
#> $a
#> [1] 1
#> 
#> $b
#> [1] "c"
#> 
#> $c
#> [1] 1 2 3

`[<-` <- function(x, idx, value) {
  ret <- base::`[<-`(x, idx, value)
  names(ret) <- base::`[<-`(names(ret),idx, names(value))
  ret
}
names(z[2]) <- "b2" #does work
z
#> $a
#> [1] 1
#> 
#> $b2
#> [1] "c"
#> 
#> $c
#> [1] 1 2 3
rm(`[<-`) # please don't use this in real life! At least, implement a S3 method (`[<-.yourclass`) instead

这样,您的两种方法都会起作用。

掌握了这些知识,您还可以创建一个函数来仅更改一个名称

`name<-` <- function(x,i,value) {
  names(x)[i] <- value
  x # `function<-` functions return a modified version of their first argument which will be bound to the name of the first arguments symbol
}


name(z, 3) <- "c4"
z
#> $a
#> [1] 1
#> 
#> $b
#> [1] "c"
#> 
#> $c4
#> [1] 1 2 3

创建于 2023-12-09,使用 reprex v2.0.2

© www.soinside.com 2019 - 2024. All rights reserved.