任何有效的方法来将列表名称传播到其内部向量?

时间:2019-12-20 09:25:38

标签: r

给出列表lst <- list(a = 1:2, b = 3:5)

> lst
$a
[1] 1 2

$b
[1] 3 4 5

我想为ab中的值扩展名称lst$alst$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]]))))

但是我怀疑可能还有其他更聪明,更优雅的方法。提前非常感谢您!

4 个答案:

答案 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循环是这里的一种好方法。