Reputation: 41
I often want to run an expression or call a function on each row of a tibble purely for the side-effect, without any interest in the return value. For example, I might have a tibble with a list column of data that I want to save using file names from a character column. There are of course a myriad ways to do this, but I would prefer to do it as elegantly as the other rowwise operations in dplyr (1.0). Essentially, I'm looking for an amalgam of rowwise mutate()
and purrr::walk()
. Here's an ugly approximation to what I want to do:
library(tidyverse)
dat <-
tibble(file = c("iris.csv", "mtcars.csv"),
data = list(iris, mtcars))
dat %>% rowwise() %>% mutate(x = list(write_csv(data, file))) %>% invisible()
Is there a way I can do away with the x = list(…)
stuff and explicit hiding of the return value while maintaining easy access to the "data-variables" in the function call (without ugly stuff like .x$data[[1]]
)? Suppose there was such a function (walk_rows()
?) I would expect to use it something like this:
dat %>% walk_rows(write_csv(data, file)))
I know I can do this:
dat %>% pwalk(function(dat, file) write_csv(dat, file))
But having to write the names of the data-variables twice is inelegant.
Upvotes: 4
Views: 323
Reputation: 2013
group_walk
seems to be the current dplyr way to do this. In the example from the question:
dat %>%
rowwise() %>%
group_walk(~ write_csv(.$data[[1]], .$file)))
or, using an explicit function instead of the purrr-style formula:
dat %>%
rowwise() %>%
group_walk(function(row, key) { write_csv(row$data[[1]], row$file) })
or, if you don't like the $
s,
dat %>%
rowwise() %>%
group_walk(function(row, key) {
with(row, {
write_csv(data[[1]], file)
})
})
Notes:
[[1]]
; without it, data
is a one-element list
.mutate
.group_walk
is lifecycle:experimental.Upvotes: 2
Reputation: 173803
I'm not clear if you're looking for something that's already within the tidyverse that allows what you want, or whether you're looking for an implementation of walk_rows
. I'm not aware of anything in the tidyverse that does exactly what you want, but here's an implementation of walk_rows
:
walk_rows <- function(dat, expr)
{
`%>%` <- dplyr::`%>%`
m <- as.list(match.call())[-(1:2)]
dummy <- dat %>%
dplyr::rowwise() %>%
dplyr::summarize(x = list(eval(m$expr)), .groups = "drop")
}
So you can do:
dat %>% walk_rows(write.csv(data, file))
Which quietly writes your files. Or, for example:
dat %>% walk_rows(print(paste0(file, ": ", nrow(data))))
#> [1] "iris.csv: 150"
#> [1] "mtcars.csv: 32"
Upvotes: 2