Hong Ooi Hong Ooi - 20 days ago 11
R Question

Formula from list of quoted terms

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