如何在不重新分配的情况下修改嵌套在列表中的数据框

How to modify a dataframe nested inside a list without re-assignment

我有一个包含多个元素的列表对象。一个元素是我希望修改的数据框:我想执行一些操作,例如列重命名和改变新列。

虽然一种简单的方法是提取嵌套数据框,修改它,最后将输出重新分配给原始父列表,但我想避免这种解决方案,因为它需要中间分配。

例子

数据。让我们构建一个包含多个数据对象的列表

library(tibble)

my_list <- lst(letters, mtcars, co2, uspop, iris)

任务。

  1. 我想修改my_list$mtcars为:

    • 重命名 cyl
    • 计算一个新列,对 mpg 列中的值求平方根
  2. 我想修改my_list$iris为:

    • select 以 sepal
    • 开头的列
    • 将它们重命名为小写

    最终我希望得到一个与原始 my_list 相同的列表对象,除了我对 mtcarsiris.[=23= 所做的更改之外]

我的尝试。现在,我知道实现此目的的唯一方法涉及重新分配:

library(dplyr)

my_list$mtcars <-
  my_list$mtcars %>%
  rename("Number of cylinders" = cyl) %>%
  mutate(sqrt_of_mpg = sqrt(mpg))

my_list$iris <- 
  my_list$iris %>%
  select(starts_with("Sepal")) %>%
  rename_with(tolower)

我的问题: 给定 my_list,我如何通过名称指向嵌套元素,指定应该发生哪些操作来修改它,并取回parent my_list 只做了那些修改?

我想象某种管道看起来像这样(只是为了了解我的大致想法)

## DEMO ##
my_list %>%
  update_element(which = "mtcars", what = rename, mutate) %>%
  update_element(which = "iris", what = select, rename)

谢谢!

你可以试试purrrmodify_at功能

library(tidyverse)
my_list %>% 
  modify_at("mtcars", ~rename(.,"Number of cylinders" = cyl) %>% 
              mutate(sqrt_of_mpg = sqrt(mpg))) %>% 
  modify_at("iris", ~select(., starts_with("Sepal")) %>%
              rename_with(tolower))

您可以使用 imap 为每次迭代传递名称和数据,但这并不接近您的总体想法。

library(dplyr)

my_list <- purrr::imap(my_list, ~{
  if(.y == 'mtcars') 
    .x %>% rename("Number of cylinders" = cyl) %>%mutate(sqrt_of_mpg = sqrt(mpg))
  else if(.y == 'iris') 
    .x %>% select(starts_with("Sepal")) %>% rename_with(tolower)
  else .x
})