将嵌套列表的第二个元素设置为列表元素的名称(purrr)

时间:2019-09-24 20:51:15

标签: list tidyverse nested-lists purrr

我有一个包含要填充的空元素的列表的命名列表:

List of 3
 $ name1:List of 3
  ..$ A: NULL
  ..$ B: NULL
  ..$ C: NULL
 $ name2:List of 3
  ..$ I: NULL
  ..$ J: NULL
  ..$ K: NULL
 $ name3:List of 3
  ..$ P: NULL
  ..$ Q: NULL
  ..$ R: NULL

我可以为每个子列表的第二个元素分配一个向量:

testlist <- map(testlist, ~modify_at(.x, 2, ~c("one", "two", "three")))
str(testlist)

List of 3
 $ name1:List of 3
  ..$ A: NULL
  ..$ B: chr [1:3] "one" "two" "three"
  ..$ C: NULL
 $ name2:List of 3
  ..$ I: NULL
  ..$ J: chr [1:3] "one" "two" "three"
  ..$ K: NULL
 $ name3:List of 3
  ..$ P: NULL
  ..$ Q: chr [1:3] "one" "two" "three"
  ..$ R: NULL

但是现在我想将列表中每个元素的名称分配给每个子列表的第三个元素(即,该元素的名称在循环的每一步都会有所不同)。所需的输出:

List of 3
 $ name1:List of 3
  ..$ A: NULL
  ..$ B: NULL
  ..$ C: chr "name1"
 $ name2:List of 3
  ..$ I: NULL
  ..$ J: NULL
  ..$ K: chr "name2"
 $ name3:List of 3
  ..$ P: NULL
  ..$ Q: NULL
  ..$ R: chr "name3"

对先前功能的简单修改不起作用:

map(testlist, ~modify_at(.x, 3, ~.x))

当我这样做时,每个子列表的第三个元素完全消失:

List of 3
 $ name1:List of 2
  ..$ A: NULL
  ..$ B: NULL
 $ name2:List of 2
  ..$ I: NULL
  ..$ J: NULL
 $ name3:List of 2
  ..$ P: NULL
  ..$ Q: NULL

我尝试了各种组合,包括set_names(.x)甚至map2:

map2(testlist, names(testlist), ~modify_at(.x, 3, ~.y))

(最后一位等效于imap)

但是没有任何效果,其中许多导致删除了每个子列表的第三个元素。而且主列表的名称没有错。

names(testlist)
[1] "name1" "name2" "name3"

我不太确定那里发生了什么。任何提示和帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

类似于R - Composite functions vs piped functions in `purrr::map()`,使用匿名函数而不是公式(〜)表示法更容易了解发生了什么。

开始

testlist  <- list(name1=list(NULL,NULL,NULL), name2=list(NULL,NULL,NULL),
name3=list(NULL,NULL,NULL))

str(testlist)
#> List of 3
#>  $ name1:List of 3
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>  $ name2:List of 3
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL
#>  $ name3:List of 3
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : NULL

然后重新创建您的第一个示例 testlist2 <- map(testlist, ~modify_at(.x, 2, ~c("one", "two", "three")))可以重写为testlist2_expand <- map(testlist, function(x) modify_at(x, 2, function(y) y=c("one", "two", "three"))),它为

str(testlist2_expand)提供相同的输出
#> List of 3
#>  $ name1:List of 3
#>   ..$ : NULL
#>   ..$ : chr [1:3] "one" "two" "three"
#>   ..$ : NULL
#>  $ name2:List of 3
#>   ..$ : NULL
#>   ..$ : chr [1:3] "one" "two" "three"
#>   ..$ : NULL
#>  $ name3:List of 3
#>   ..$ : NULL
#>   ..$ : chr [1:3] "one" "two" "three"
#>   ..$ : NULL

但是您的第二个示例map(testlist, ~modify_at(.x, 3, ~.x))确实是 map(testlist, function(x) modify_at(x, 1, function (y) y = y))

我认为您希望.x被重用,但这是一个新作用域中的新变量。它从未定义,因此被评估为NULL,导致map(testlist, function(x) modify_at(x, 1, function (y) NULL))并删除了元素

做你想做的事

testlist2 <- map2(testlist, names(testlist), function(x,y) modify_at(x, 3, function (z) z = y))
str(testlist2)
#> List of 3
#>  $ name1:List of 3
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : chr "name1"
#>  $ name2:List of 3
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : chr "name2"
#>  $ name3:List of 3
#>   ..$ : NULL
#>   ..$ : NULL
#>   ..$ : chr "name3"