如何在R中以有效的方式重命名列表列表中的元素?

时间:2018-06-03 04:16:19

标签: r

我目前有一个包含大约5000个元素的大型列表。可重现的例子如下:

List.5000 <- replicate(5000, c(list(A='A',value.A=10),list(B='B',value.B=20)), simplify = F)

有:

> List.5000
[[1]]
[[1]]$A
[1] "A"

[[1]]$value.A
[1] 10

[[1]]$B
[1] "B"

[[1]]$value.B
[1] 20


[[2]]
[[2]]$A
[1] "A"

[[2]]$value.A
[1] 10

[[2]]$B
[1] "B"

[[2]]$value.B
[1] 20
....

当我致电names(List.5000)时,它会返回NULL。但是当我打电话给names(List.5000[[1]])时,它会给出:

"A"       "value.A" "B"       "value.B"

我想将名称"B"更改为"Z"。有没有办法在不诉诸创建新列表的情况下执行此操作,然后循环和重构?

3 个答案:

答案 0 :(得分:4)

for(i in seq_along(List.5000))
  names(List.5000[[i]])[names(List.5000[[i]]) == 'B'] <-  'Z'

或者,如果您更喜欢lapply / map

List.5000 <- lapply(List.5000, 
                    function(x) {names(x)[names(x) == 'B'] <-  'Z'; x})

library(purrr)
List.5000 <- map(List.5000, ~{names(.)[names(.) == 'B'] <-  'Z'; .})

如果这些名字真的完全相同,那么

ind <- names(List.5000[[1]]) == 'B'
for(i in seq_along(List.5000))
  names(List.5000[[i]])[ind] <-  'Z'

括号语法快一点:

x <- List.5000[[1]]
microbenchmark(
  sub = names(x) <- sub("^B$", "Z", names(x))
  , ifelse = names(x) <- ifelse(names(x) == 'B', 'Z', names(x))
  , stringi = names(x) <- str_replace(names(x), "^B$", "Z")
  , replace = names(x) <- replace(names(x), names(x) == 'B', 'Z')
  , bracket = names(x)[names(x) == 'B'] <-  'Z'
)
# Unit: microseconds
# expr        min       lq      mean   median       uq     max neval
# sub      22.041  31.2265  58.24097  46.9650  78.5075 373.637   100
# ifelse   13.309  22.4110  44.00665  30.2235  65.1395 113.693   100
# stringi 153.880 313.0400 346.41543 358.4795 383.4130 631.354   100
# replace   4.067   6.3205  13.09022   8.1760  11.9280  54.075   100
# bracket   3.246   4.5265  10.38177   5.9180   7.9925  55.278   100

仍然有点不满意,因为这些方法都没有修改列表。

答案 1 :(得分:3)

您可以使用purrr:map()sub()

library(purrr)

map(List.5000, ~sub("^B$", "Z", names(.x)))

或使用stringr::str_replace保持tidyverse语法:

library(stringr)

map(List.5000, ~str_replace(names(.x), "^B$", "Z"))

您甚至不需要purrr,您可以使用lapply,但我确实发现purrr语法更清晰:

lapply(List.5000, function(x) sub("^B$", "2", names(x)))

<强>更新
根据Ryan的评论,如果您确实想要更改列表名称本身而不是值,则可以使用此代码:

change_names <- function(x) {
  names(x) <- sub("^B$", "Z", names(x))
  x
}
map(List.5000, ~change_names(.x))

[[1]]
[[1]]$A
[1] "A"

[[1]]$value.A
[1] 10

[[1]]$Z
[1] "B"

[[1]]$value.B
[1] 20
...

答案 2 :(得分:2)

我们可以使用plyr::rename

out <- lapply(List.5000, plyr::rename, c("B" =  "Z"))