I was interested in the question for the sake of debugging (wanting to save intermediate results so that I can inspect and manipulate them from the console without having to separate the pipeline into two pieces which is cumbersome. So, for my purposes, the only problem with the OP's solution original solution was that it was slightly verbose.
This as can be fixed by defining a helper function:
to_var <- function(., ..., env=.GlobalEnv) {
var_name = quo_name(quos(...)[[1]])
assign(var_name, ., envir=env)
.
}
Which can then be used as follows:
df <- data.frame(a = LETTERS[1:3], b=1:3)
df %>%
filter(b < 3) %>%
to_var(tmp) %>%
mutate(b = b*2) %>%
bind_rows(tmp)
# tmp still exists here
That still uses the global environment, but you can also explicitly pass a more local environment as in the following example:
f <- function() {
df <- data.frame(a = LETTERS[1:3], b=1:3)
env = environment()
df %>%
filter(b < 3) %>%
to_var(tmp, env=env) %>%
mutate(b = b*2) %>%
bind_rows(tmp)
}
f()
# tmp does not exist here
The problem with the accepted solution is that it didn't seem to work out of the box with tidyverse pipes.
G. Grothendieck's solution doesn't work for the debugging use case at all. (update: see G. Grothendieck's comment below and his updated answer!)
Finally, the reason assign("tmp", .) %>%
doesn't work is that the default 'envir' argument for assign()
is the "current environment" (see documentation for assign) which is different at each stage of the pipeline. To see this, try inserting { print(environment()); . } %>%
into the pipeline at various points and see that a different address is printed each time. (It is probably possible to tweak the definition of to_var so that the default is the grandparent environment instead.)