给出列表lst <- list(a = 1:2, b = 3:5)
> lst
$a
[1] 1 2
$b
[1] 3 4 5
我想为a
和b
中的值扩展名称lst$a
和lst$b
,
> lst
$a
a a
1 2
$b
b b b
3 4 5
我的愚蠢代码如下:
lst[] <-lapply(seq(lst),function(k) lst[[k]] <- setNames(lst[[k]], rep(names(lst[k]),length(lst[[k]]))))
但是我怀疑可能还有其他更聪明,更优雅的方法。提前非常感谢您!
答案 0 :(得分:4)
用两个参数定义一个自定义函数
f <- function(x, y) setNames(x, rep(y, times = length(x)))
并使用Map
Map(f, lst, names(lst))
结果
#$a
#a a
#1 2
#
#$b
#b b b
#3 4 5
答案 1 :(得分:3)
您也可以尝试:
Map(setNames, lst, Map(rep, names(lst), lengths(lst)))
$a
a a
1 2
$b
b b b
3 4 5
答案 2 :(得分:2)
我们也可以直接执行此操作,而无需应用族或for
循环
vals <- rep(names(lst), lengths(lst))
split(setNames(unlist(lst), vals), vals)
#$a
#a a
#1 2
#$b
#b b b
#3 4 5
答案 3 :(得分:1)
例如,您可以使用简单的for
循环来操作列表中的元素:
nms <- names(lst)
for (i in seq_along(lst)) {
names(lst[[i]]) <- rep(nms[i], length(lst[[i]]))
}
这已经非常快了。
以下是与其他答案的比较:
forloop <- function() {
nms <- names(lst)
for (i in seq_along(lst)) {
names(lst[[i]]) <- rep(nms[i], length(lst[[i]]))
}
lst
}
map_approach <- function() {
Map(setNames, lst, Map(rep, names(lst), lengths(lst)))
}
ronaks_approach <- function() {
vals <- rep(names(lst), lengths(lst))
split(setNames(unlist(lst), vals), vals)
}
res <- bench::mark(
forloop(),
map_approach(),
ronaks_approach(),
check = TRUE
)
结果如下:
res
#> # A tibble: 3 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 forloop() 3.7µs 4.36µs 216113. 4.26MB 21.6
#> 2 map_approach() 15µs 17.69µs 53871. 3.64KB 21.6
#> 3 ronaks_approach() 50.6µs 57.7µs 16809. 34.62KB 14.4
summary(res, relative = TRUE)
#> # A tibble: 3 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 forloop() 1 1 12.9 1199. 1.50
#> 2 map_approach() 4.05 4.06 3.20 1 1.49
#> 3 ronaks_approach() 13.7 13.2 1 9.51 1
由于该示例不切实际,因此这是另一个具有较大示例的运行({@ lst <- rep(lst, 50000)
和names(lst) <- make.names(names(lst), unique = TRUE)
,因为@Ronak的方法需要唯一的名称):
res
#> # A tibble: 3 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 forloop() 185ms 302ms 3.31 781.3KB 8.28
#> 2 map_approach() 507ms 507ms 1.97 1.91MB 3.94
#> 3 ronaks_approach() 654ms 654ms 1.53 26.88MB 0
summary(res, relative = TRUE)
#> Warning: Some expressions had a GC in every iteration; so filtering is disabled.
#> # A tibble: 3 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 forloop() 1 1 2.17 1 Inf
#> 2 map_approach() 2.74 1.68 1.29 2.50 Inf
#> 3 ronaks_approach() 3.53 2.17 1 35.2 NaN
答案之间没有太大区别,但是我的直觉似乎很正确,简单的for
循环是这里的一种好方法。