Apply a Function Recursively

DESCRIPTION:

Recursively apply the function f to object, to all its elements, and so on.

USAGE:

rapply(object, f, classes, deflt, how, ...)

REQUIRED ARGUMENTS:

object
The name of the object to which you want to apply the function recursively.
f
The name of the function to apply. Must be a function of one argument only.

OPTIONAL ARGUMENTS:

classes
The classes in the object to which you want to apply the function. By default, "ANY".
deflt
argument, default = NULL.
how
Controls the results. See the DETAILS section for more information. By default, "unlist".
...
additional arguments suitable to the method.

VALUE:

Determined by f and how. See the DETAILS section for more information.

DETAILS:

Calls to f are made only if the current element extends one of the classes. Otherwise, it is as if the function returned deflt.

There are three approaches to treat the results, controlled by how: The default "unlist" takes all the returned values and unlists them; "replace" replaces any applicable element of object, at any level, with the value of the call (in which case deflt is ignored); "list" makes a list at every recursive level, first of the values generated from children of this level, and then of the call to f applied to this level itself. You need to supply only the first character.

The first two approaches of calling this function using how are much easier to understand:

If you set how="unlist", and deflt is NULL, rapply returns just the unlisted, concatenated values. For example, use this call for a function that returns a scalar result.

If you set how="replace", you can update elements of a tree-like object at all levels. Only the elements that match classes are changed.

If neither of these approaches works for you, use the third approach, but note that you probably will need to disentangle the result, maybe by another call to rapply.

SEE ALSO:

, , , , , .

EXAMPLES:

# The following function takes an expression (typically a function) as 
# input and changes all calls for the form
#    log(x, base)
# (which is legal in R) to call logb(x, base) instead.  It does 
# not alter calls to log that have only one argument.

fixTwoArgLog <- function(expr)
{
        rapply(list(expr), how = "replace", classes = "call", f = function(e)
        {
                if(identical(e[[1]], as.name("log")) && length(e) == 3) {
                        e[[1]] <- as.name("logb")
                        e <- as.call(e)
                }
                e
        }
        )[[1]]
}

# When you call this function:
fixTwoArgLog(Quote(log(x)/log(2) == log(x, 2)))

# It results in the following:
# log(x)/log(2) == logb(x, 2)