Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R remove redundant parentheses from formula string or expression

I have many formula strings similar to this:

str <- "( ((  A  ) *  J ) - ((  J  ) *  G  ) ) /  Z "

There are many parentheses which don't need to be there, (A*J - J*G)/Z is sufficient. Is there a function or package in R that can take care of this?

I tried functions for R expressions and as well as.formula but did not find what I need.

like image 519
user1981275 Avatar asked Jun 21 '13 17:06

user1981275


2 Answers

We can use R parser to do the job. The trick is that R knows when parentheses are needed based on the parse tree, so we can simply remove them from the tree:

See this:

simplify <- function(e)
{
    if( mode(e) %in% c("name","numeric") ) return(e)

    op <- as.character(e[[1]])

    if( op == "(" ) return(simplify(e[[2]]))

    if( op %in% c("+","-","*","/","^") ) return(call(op, simplify(e[[2]]), simplify(e[[3]])))
}

simplifytext <- function(s) deparse(simplify(parse(text=s)[[1]]))

Inputs:

str <- "( ((  A  ) *  J ) - ((  J  ) *  G  ) ) /  Z "
str2 <- gsub("-", "/", gsub("*", "+", str, fixed=TRUE))

Results:

> str2
[1] "( ((  A  ) +  J ) / ((  J  ) +  G  ) ) /  Z "

> simplifytext(str)
[1] "(A * J - J * G)/Z"
> simplifytext(str2)
[1] "(A + J)/(J + G)/Z"
like image 171
Ferdinand.kraft Avatar answered Nov 12 '22 22:11

Ferdinand.kraft


Here are a couple of approaches:

R parsing

rmParen <- function(e) {
    if (length(e) > 1) {
        if (identical(e[[1]], as.symbol("("))) e <- e[[2]]
        if (length(e) > 1) for (i in 1:length(e)) e[[i]] <- Recall(e[[i]])
    }
    e
}

s <- "( ((  A  ) *  J ) - ((  J  ) *  G  ) ) /  Z "
rmParen(parse(text = s)[[1]])

The last line returns:

(A * J - J * G)/Z

This works in all cases I tried but you might want to test it out a bit more.

If you want a character string as the return value then use deparse as in deparse(rmParen(parse(text = s)[[1]])). Note that deparse has a width.cutoff argument which is set to 60 by default but can be set to be larger if the actual expressions exceed that length.

Ryacas

library(Ryacas)

s <- "( ((  A  ) *  J ) - ((  J  ) *  G  ) ) /  Z "
Simplify(s)

The last line returns:

expression((A - G) * J/Z)

Note that its actually the print method that invokes the computation so if you want to save it then try yacas(Simplify(s))$text or as.character(yacas(Simplify(s))) .

ADDED: Ryacas solution.

like image 36
G. Grothendieck Avatar answered Nov 13 '22 00:11

G. Grothendieck