Hong Ooi - 20 days ago 11

R Question

Say I have a list of quoted terms:

`l <- list(quote(x), quote(y), quote(I(z + 10)))`

and I want to turn this into a (one-sided) formula:

`~ x + y + I(z + 10)`

The simplest way to do this would be to turn everything into text and build the formula from scratch, ie, deparse/reparse:

`formula(paste("~", paste(l, collapse="+")))`

which, behind the scenes, is equivalent to

`formula(paste("~", paste(sapply(l, deparse), collapse="+")))`

But that seems a bit inelegant, and possibly prone to parsing screwups. Is there a way to obtain the formula with pure language manipulation?

Answer Source

It's possible to do this in a purely symbolic manner by building up the formula RHS term by term.

```
l <- list(quote(x), quote(y), quote(I(z + 10)))
out <- l[[1]]
for(i in seq_along(l)[-1])
{
out <- substitute(a + b, list(a=out, b=l[[i]]))
}
out <- call("~", out)
out
# ~x + y + I(z + 10)
```

Note that `out`

*looks* like a formula, but is actually of class (and mode) `call`

. To turn it into an actual formula, use `as.formula`

:

```
f <- as.formula(out)
```

However, it can sometimes be advantageous to leave the output as a call object. In particular, if the number of terms is very large, creating the formula can cause a stack overflow:

```
X <- paste0("x", 1:1e5)
X <- lapply(X, as.name)
out <- X[[1]]
for(i in seq_along(X)[-1])
{
out <- substitute(a + b, list(a=out, b=X[[i]]))
}
# this still works
out <- call("~", out)
f <- as.formula(out)
# Error: protect(): protection stack overflow
```