3

How can I parse and evaluate a column of string expressions in R as part of a pipeline?

In the example below, I produce my desired column, evaluated. But I know this isn't the right approach. I tried taking a tidyverse approach. But I'm just very confused.

library(tidyverse) df <- tibble(name = LETTERS[1:3], to_evaluate = c("1-1+1", "iter+iter", "4*iter-1"), evaluated = NA) iter = 1 for (i in 1:nrow(df)) { df[i,"evaluated"] <- eval(parse(text=df$to_evaluate[[i]])) } print(df) # # A tibble: 3 x 3 # name to_evaluate evaluated # <chr> <chr> <dbl> # 1 A 1-1+1 1 # 2 B iter+iter 2 # 3 C 4*iter-1 3 

As part of a pipeline, I tried:

df %>% mutate(evaluated = eval(parse(text=to_evaluate))) df %>% mutate(evaluated = !!parse_exprs(to_evaluate)) df %>% mutate(evaluated = parse_exprs(to_evaluate)) df %>% mutate(evaluated = eval(parse_expr(to_evaluate))) df %>% mutate(evaluated = parse_exprs(to_evaluate)) df %>% mutate(evaluated = eval(parse_exprs(to_evaluate))) df %>% mutate(evaluated = eval_tidy(parse_exprs(to_evaluate))) 

None of these work.

1

3 Answers 3

4

You can try:

df %>% rowwise() %>% mutate(iter = 1, evaluated = eval(parse(text = to_evaluate))) %>% select(-iter) name to_evaluate evaluated <chr> <chr> <dbl> 1 A 1-1+1 1 2 B iter+iter 2 3 C 4*iter-1 3 

Following this logic, also other possibilities could work. Using rlang::parse_expr():

df %>% rowwise() %>% mutate(iter = 1, evaluated = eval(rlang::parse_expr(to_evaluate))) %>% select(-iter) 

On the other hand, I think it is important to quote @Martin Mächler:

The (possibly) only connection is via parse(text = ....) and all good R programmers should know that this is rarely an efficient or safe means to construct expressions (or calls). Rather learn more about substitute(), quote(), and possibly the power of using do.call(substitute, ......).

Sign up to request clarification or add additional context in comments.

4 Comments

You can do all of this with mutate and pmap and well. df %>% mutate(evaluated = pmap_dbl(., function(name, to_evaluate, evaluated) eval(parse(text=to_evaluate))))
@rpolicastro I think it is worth of a separate post, please consider posting it :)
I'll post another answer for it, thanks. Wasn't sure if it was different enough from yours to be worth it.
This simplifies your second solution a bit: iter <- 1; df %>% rowwise() %>% mutate(evaluated = eval(rlang::parse_expr(to_evaluate))). No need to define iter in the pipe.
2

Here's a slightly different way that does everything within mutate.

df %>% mutate( evaluated = pmap_dbl(., function(name, to_evaluate, evaluated) eval(parse(text=to_evaluate))) ) # A tibble: 3 x 3 name to_evaluate evaluated <chr> <chr> <dbl> 1 A 1-1+1 1 2 B iter+iter 2 3 C 4*iter-1 3 

Comments

1

Note that values of additional variables (such as iter=1 in your case) can be passed directly to eval():

df %>% mutate( evaluated = map_dbl(to_evaluate, ~eval(parse(text=.x), list(iter=1))) ) 

One advantage is that it automatically restricts the scope of the variable, keeping its value right next to where it is used.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.