What is the difference between with and within in R?
I find simple examples often work to highlight the difference. Something like:
df <- data.frame(a=1:5,b=2:6)df a b1 1 22 2 33 3 44 4 55 5 6with(df, {c <- a + b; df;} ) a b1 1 22 2 33 3 44 4 55 5 6within(df, {c <- a + b; df;} )# equivalent to: within(df, c <- a + b)# i've just made the return of df explicit # for comparison's sake a b c1 1 2 32 2 3 53 3 4 74 4 5 95 5 6 11
The documentation is quite clear about the semantics and return values (and nicely matches the everyday meanings of the words “with” and “within”):
Value:
For ‘
with
’, the value of the evaluated ‘expr
’. For ‘within
’, the modified object.
Since your code doesn’t modify anything inside baseball
, the unmodified baseball
is returned. with
on the other hand doesn’t return the object, it returns expr
.
Here’s an example where the expr
ession modifies the object:
> head(within(cars, speed[dist < 20] <- 1))
speed dist1 1 22 1 103 1 44 7 225 1 166 1 10
As above, with
returns the value of the last evaluated expression. It is handy for one-liners such as:
with(cars, summary(lm (speed ~ dist)))
but is not suitable for sending multiple expressions.
I often find within
useful for manipulating a data.frame
or list
(or data.table
) as I find the syntax easy to read.
I feel that the documentation could be improved by adding examples of use in this regard, e.g.:
df1 <- data.frame(a=1:3, b=4:6, c=letters[1:3])## library("data.table") ## df1 <- as.data.table(df1)df1 <- within(df1, { a <- 10:12 b[1:2] <- letters[25:26] c <- a})df1
giving
a b c1: 10 y 102: 11 z 113: 12 6 12
and
df1 <- as.list(df1)df1 <- within(df1, { a <- 20:23 b[1:2] <- letters[25:26] c <- paste0(a, b)})df1
giving
$a[1] 20 21 22 23$b[1] "y" "z" "6"$c[1] "20y" "21z" "226" "23y"
Note also that methods("within")
gives only these object types, being:
within.data.frame
within.list
- (and
within.data.table
if the package is loaded).
Other packages may define additional methods.
Perhaps unexpectedly for some, with
and within
are generally not appropriate choices when manipulating variables within defined environments...
To address the comment - there is no within.environment
method. Using with
requires you to have the function you're calling within the environment, which somewhat defeats the purpose for me e.g.
df1 <- as.environment(df1)## with(df1, ls()) ## Errorassign("ls", ls, envir=df1)with(df1, ls())