eapply() in R: Apply Functions to Environment Variables
The eapply() function in base R applies a function to every variable bound in an environment and returns a named list of results. It is the apply-family member built specifically for environments, where lapply() would need an explicit as.list() conversion first.
eapply(env, FUN) # apply FUN to every binding eapply(env, FUN, all.names = TRUE) # include hidden (.dotted) names eapply(env, FUN, USE.NAMES = FALSE) # drop the binding names eapply(globalenv(), object.size) # size of every global object eapply(env, function(x) class(x)[1]) # class of each binding eapply(env, summary) # summary of every variable eapply(asNamespace("stats"), is.function) # scan a package namespace
Need explanation? Read on for examples and pitfalls.
What eapply() does in one sentence
eapply(env, FUN, ..., all.names, USE.NAMES) iterates over every name bound in env, applies FUN to each value, and returns a named list. It is the only apply-family function that takes an environment directly; the others need as.list(env) first.
An environment in R is a set of name-to-value bindings, like a hash map. eapply() walks them, evaluates each (forcing promises and active bindings), and returns the results named by binding, unless USE.NAMES = FALSE.
Syntax and arguments
eapply(env, FUN, ..., all.names = FALSE, USE.NAMES = TRUE) takes one required environment, one required function, and three optional controls. Extra arguments after FUN flow into FUN via ..., exactly like in lapply().
The environment e has three bindings. eapply() visits each, calls length() on the value, and returns a list with the original names. Output order is not guaranteed (see Pitfall 1).
| Argument | Purpose | Common values |
|---|---|---|
env |
Environment to iterate over | new.env(), globalenv(), asNamespace("pkg"), a function's environment() |
FUN |
Function applied to each binding's value | length, class, object.size, summary, custom lambda |
... |
Extra arguments passed to FUN |
na.rm = TRUE, digits = 2, any FUN-specific arg |
all.names |
Whether to visit hidden bindings (names starting with .) |
FALSE (default), TRUE |
USE.NAMES |
Whether to label the result with binding names | TRUE (default), FALSE |
Five common patterns
1. Audit every object in the global workspace
Pairing eapply() with object.size() is the standard recipe for finding memory hogs. Replace ga with globalenv() in a real session; unlist() collapses the named list into a sortable vector.
2. Get the class of every variable
class(x)[1] keeps only the primary class for objects with multiple classes. Useful for a flat one-row-per-binding inventory.
3. Reveal hidden bindings with all.names
Dotted names (.x, ..y) are conventionally hidden in R, mirroring ls(). Pass all.names = TRUE when debugging internal package code or environments built by local() and other meta-programming helpers.
4. Scan a package namespace
asNamespace() returns the environment backing a package's namespace. Combined with eapply(), this builds catalogs of functions or datasets without ls() + get() loops. Dotted names appear because namespace internals are visited; order is hash-driven.
5. Use an environment as a mutable counter store
Environments are R's built-in mutable hash maps. After mutating bindings in a loop, eapply(env, identity) is the canonical way to materialize the final state as a list.
eapply() vs lapply, ls, and as.list
Each function answers a different "iterate over an environment" question. The table below sorts the alternatives by what they return and how they treat names.
| Function | Input | Output | Use when |
|---|---|---|---|
eapply() |
Environment | Named list of FUN(value) | You want to apply a function to every binding's value |
lapply(as.list(env), FUN) |
Environment (via conversion) | Named list of FUN(value) | You need deterministic order or want to chain with other list tools |
ls(env) |
Environment | Sorted character vector of names | You only need names, not values |
as.list(env) |
Environment | Named list of values (no FUN) | You want the raw values to inspect or save |
mget(ls(env), env) |
Environment | Named list of values, in ls() order |
You want values back in a controlled order |
The mental model: pick eapply() when you have an environment AND want to map a function over its values. For names only, use ls(). For raw values, use as.list(). When iteration order matters, convert to a list first.
ls() returns. If your downstream code depends on a specific order, wrap the result: eapply(env, FUN)[ls(env)] reorders it alphabetically.Common pitfalls
Three quirks of eapply trip up most users. Each has a fix that takes one extra line.
Pitfall 1: Output order is unpredictable
Two calls to eapply() on the same environment may produce results in different name orders. This surprises users who assume insertion or alphabetical order.
Reorder explicitly with result[ls(env)] whenever the consumer expects a fixed name order. Tests, snapshots, and reports especially need this guard.
Pitfall 2: Hidden names are skipped by default
Bindings whose name starts with a dot are invisible to eapply() unless you set all.names = TRUE. This matches ls()'s behavior but bites debuggers who forgot the flag.
Always pass all.names = TRUE when auditing environments built by package code, local(), or anything that uses dotted names for internal state.
Pitfall 3: Active bindings get evaluated
eapply() forces every binding, so active bindings (those created with makeActiveBinding()) run their function each time. This can be slow or have side effects.
Each eapply() call increments counter because visiting now invokes its underlying function. To skip active bindings, filter with Filter(Negate(bindingIsActive), ls(e)) before calling.
Try it yourself
Try it: Build an environment ex_env with three numeric vectors of different lengths, then use eapply() to get the mean of each. Save the result, reordered alphabetically by name, to ex_means.
Click to reveal solution
Explanation: eapply(ex_env, mean) returns a named list of three means in hash order. Subsetting with [ls(ex_env)] reorders the list by ls()'s alphabetical default, giving a stable, predictable name order. The c element value will vary because rnorm(100) is random; only the names and structure are deterministic.
Related apply functions in R
- base lapply: single-level apply for lists and vectors, returns a list.
- base sapply: single-level apply with auto-simplification.
- base vapply: single-level apply with a strict type and length contract.
- base mapply: apply a function across multiple parallel vectors.
- base rapply: recursive apply over nested lists.
- R Environments: the broader hub on environments, scoping, and lookup.
External reference: the R Language Definition on eapply is the canonical source for argument semantics and the underlying iteration algorithm.
FAQ
What does eapply do in R?
eapply() applies a function to every binding in an environment and returns a named list. The signature is eapply(env, FUN, ..., all.names = FALSE, USE.NAMES = TRUE). Use it to audit the global workspace, scan a package namespace, or post-process an environment used as a mutable hash map. It is built into base R; no package needed.
What is the difference between eapply and lapply?
lapply() iterates over elements of a list or atomic vector. eapply() iterates over bindings of an environment. Environments are unordered hash maps; lists are ordered sequences. lapply(as.list(env), FUN) mimics eapply(env, FUN) but with deterministic order. Use eapply() for the cleanest syntax when the input is already an environment.
Does eapply preserve order in R?
No. eapply() walks bindings in hash-table order, not insertion or alphabetical. Two runs on the same environment can return results in different orders. Reorder explicitly with eapply(env, FUN)[ls(env)] for an alphabetical result. For deterministic iteration, convert first with as.list(env) then call lapply().
Can eapply access hidden variables in R?
Yes, with all.names = TRUE. By default, bindings whose names start with a dot (.cache, .private) are skipped, matching ls()'s default behavior. Pass all.names = TRUE to include them. This matters when inspecting environments built by package internals or local() blocks that use dotted names for private state.
How do I apply a function to all objects in the global environment?
Pass globalenv() (or .GlobalEnv) as the first argument: eapply(globalenv(), object.size) returns the memory footprint of every global object. Pair with sort(unlist(...)) to rank by size. Add all.names = TRUE to include hidden globals. Standard recipe for finding memory leaks during an interactive session.