递归更改R中嵌套列表中的名称
recursively change names in nested lists in R
我在 R 的嵌套列表结构中有数据,我想使用查找 table 来更改名称,无论它们在结构中的什么位置。
例子
# build up an example
x <- as.list(c("a" = NA))
x[[1]] <- vector("list", 4)
names(x[[1]]) <- c("b","c","d","e")
x$a$b <- vector("list", 2)
names(x$a$b) <- c("d","f")
x$a$c <- 3
x$a$d <- 27
x$a$e <- "d"
x$a$b$d <- "data"
x$a$b$f <- "more data"
# make a lookup table for names I want to change from; to
lkp <- data.frame(matrix(data = c("a","z","b","bee","d","dee"),
ncol = 2,
byrow = TRUE), stringsAsFactors = FALSE)
names(lkp) <- c("from","to")
上面的输出
> x
$a
$a$b
$a$b$d
[1] "data"
$a$b$f
[1] "more data"
$a$c
[1] 3
$a$d
[1] 27
$a$e
[1] "d"
> lkp
from to
1 a z
2 b bee
3 d dee
这是我为 仅 第一级想出的方法:
> for(i in 1:nrow(lkp)){
+ names(x)[names(x) == lkp$from[[i]]] <- lkp$to[[i]]
+ }
> x
$z
$z$b
$z$b$d
[1] "data"
$z$b$f
[1] "more data"
$z$c
[1] 3
$z$d
[1] 27
$z$e
[1] "d"
所以这很好用,但使用了一个循环,并且只在第一级到达。我已经尝试了各种版本的 *apply 世界,但还没有得到有用的东西。
提前感谢您的任何想法
编辑:
有趣的是,在尝试访问和修改名称时,rapply 惨败(或者,我的尝试惨败!)。这是一个尝试将所有名称更改为相同的示例
> namef <- function(x) names(x) <- "z"
> rapply(x, namef, how = "list")
$a
$a$b
$a$b$d
[1] "z"
$a$b$f
[1] "z"
$a$c
[1] "z"
$a$d
[1] "z"
$a$e
[1] "z"
我使用 character
向量代替您 data.frame
进行查找,但如果您真的想要 data.frame
.[=14=,更改它会很容易]
lkp2 <- lkp$to
names(lkp2) <- lkp$from
rename <- function(nested_list) {
found <- names(nested_list) %in% names(lkp2)
names(nested_list)[found] <- lkp2[names(nested_list)[found]]
nested_list %>% map(~{
if (is.list(.x)) {
rename(.x)
} else {
.x
}
})
}
rename(x)
# $z
# $z$bee
# $z$bee$dee
# [1] "data"
#
# $z$bee$f
# [1] "more data"
#
#
# $z$c
# [1] 3
#
# $z$dee
# [1] 27
#
# $z$e
# [1] "d"
我不确定这是最好的方法,但它似乎可以完成工作,如果您只处理小列表(如 XML 文档),则没有必要太担心性能了。
您可能想用更好的名称来命名该函数。
使用外部包,您也可以使用 rrapply
包中的 rrapply
执行此操作(基础 rapply
的扩展):
library(rrapply) ## v1.2.1
rrapply(list(x),
classes = "list",
f = function(x) {
newnames <- lkp$to[match(names(x), lkp$from)]
names(x)[!is.na(newnames)] <- newnames[!is.na(newnames)]
return(x)
},
how = "recurse"
)[[1]]
#> $z
#> $z$bee
#> $z$bee$dee
#> [1] "data"
#>
#> $z$bee$f
#> [1] "more data"
#>
#>
#> $z$c
#> [1] 3
#>
#> $z$dee
#> [1] 27
#>
#> $z$e
#> [1] "d"
在这里,f
函数实现与 OP 的 for
循环基本相同。 how = "recurse"
告诉函数在应用 f
.
之后继续递归
请注意,输入被包装为 list(x)
,因此 f
函数也会修改列表本身的名称。
我在 R 的嵌套列表结构中有数据,我想使用查找 table 来更改名称,无论它们在结构中的什么位置。 例子
# build up an example
x <- as.list(c("a" = NA))
x[[1]] <- vector("list", 4)
names(x[[1]]) <- c("b","c","d","e")
x$a$b <- vector("list", 2)
names(x$a$b) <- c("d","f")
x$a$c <- 3
x$a$d <- 27
x$a$e <- "d"
x$a$b$d <- "data"
x$a$b$f <- "more data"
# make a lookup table for names I want to change from; to
lkp <- data.frame(matrix(data = c("a","z","b","bee","d","dee"),
ncol = 2,
byrow = TRUE), stringsAsFactors = FALSE)
names(lkp) <- c("from","to")
上面的输出
> x
$a
$a$b
$a$b$d
[1] "data"
$a$b$f
[1] "more data"
$a$c
[1] 3
$a$d
[1] 27
$a$e
[1] "d"
> lkp
from to
1 a z
2 b bee
3 d dee
这是我为 仅 第一级想出的方法:
> for(i in 1:nrow(lkp)){
+ names(x)[names(x) == lkp$from[[i]]] <- lkp$to[[i]]
+ }
> x
$z
$z$b
$z$b$d
[1] "data"
$z$b$f
[1] "more data"
$z$c
[1] 3
$z$d
[1] 27
$z$e
[1] "d"
所以这很好用,但使用了一个循环,并且只在第一级到达。我已经尝试了各种版本的 *apply 世界,但还没有得到有用的东西。
提前感谢您的任何想法
编辑: 有趣的是,在尝试访问和修改名称时,rapply 惨败(或者,我的尝试惨败!)。这是一个尝试将所有名称更改为相同的示例
> namef <- function(x) names(x) <- "z"
> rapply(x, namef, how = "list")
$a
$a$b
$a$b$d
[1] "z"
$a$b$f
[1] "z"
$a$c
[1] "z"
$a$d
[1] "z"
$a$e
[1] "z"
我使用 character
向量代替您 data.frame
进行查找,但如果您真的想要 data.frame
.[=14=,更改它会很容易]
lkp2 <- lkp$to
names(lkp2) <- lkp$from
rename <- function(nested_list) {
found <- names(nested_list) %in% names(lkp2)
names(nested_list)[found] <- lkp2[names(nested_list)[found]]
nested_list %>% map(~{
if (is.list(.x)) {
rename(.x)
} else {
.x
}
})
}
rename(x)
# $z
# $z$bee
# $z$bee$dee
# [1] "data"
#
# $z$bee$f
# [1] "more data"
#
#
# $z$c
# [1] 3
#
# $z$dee
# [1] 27
#
# $z$e
# [1] "d"
我不确定这是最好的方法,但它似乎可以完成工作,如果您只处理小列表(如 XML 文档),则没有必要太担心性能了。
您可能想用更好的名称来命名该函数。
使用外部包,您也可以使用 rrapply
包中的 rrapply
执行此操作(基础 rapply
的扩展):
library(rrapply) ## v1.2.1
rrapply(list(x),
classes = "list",
f = function(x) {
newnames <- lkp$to[match(names(x), lkp$from)]
names(x)[!is.na(newnames)] <- newnames[!is.na(newnames)]
return(x)
},
how = "recurse"
)[[1]]
#> $z
#> $z$bee
#> $z$bee$dee
#> [1] "data"
#>
#> $z$bee$f
#> [1] "more data"
#>
#>
#> $z$c
#> [1] 3
#>
#> $z$dee
#> [1] 27
#>
#> $z$e
#> [1] "d"
在这里,f
函数实现与 OP 的 for
循环基本相同。 how = "recurse"
告诉函数在应用 f
.
请注意,输入被包装为 list(x)
,因此 f
函数也会修改列表本身的名称。