How to use multiple result values from a function in R? - r

I have the following code in R:
a <- 2
evaluate <- function(x){
b <- 2*x
c <- 3*x
d <- 4*x
out <- list("b" = b, "c" = c, "d" = d)
return(out)
}
evaluate(a)
I obtain something like
$b
[1] 4
$c
[1] 6
$d
[1] 8
How can I compute something like b + c + d ?

so many options
# with
with(evaluate(a), b + c + d)
[1] 18
# unlist the unnamed output object
sum(unlist(evaluate(a)))
[1] 18
# subset a named output object
result <- evaluate(a)
result$b + result$c + result$d
[1] 18
# subset an unnamed output object
evaluate(a)$b + evaluate(a)$c + evaluate(a)$d
[1] 18
# custom function with fancy arguments
f <- function(...) {
args <- unlist(...)
sum(args)
}
f(evaluate(a))
[1] 18
Also, +1 from: #Gregor (double-bracket list subsetting)
result[["b"]] + result[["c"]] + result[["d"]]
[1] 18

In R you can access list members using $ operator, followed by member name so, in your code, for example:
result = evaluate(a)
result$b + result$c + result$d

Your function returns a list. You could return a vector and then use the sum() function to compute the sum of the elements in the vector. If you must use a list, the 'Reduce()` function can work.
l <- list(2, 3, 4)
v <- c(2,3,4)
sum(v) # returns 9
Reduce("+", l) # returns 9

Related

How to iterate over a list of lists in R?

I am new to R and not able to find the counter code in R for the following Python code.
Please help
list1 = [10, 20] # or a tuple
list2 = [30, 40] # or a tuple
mylist = [list1, list2] # can be tuple of tuples also
for _list in mylist:
a = _list[0]
b = _list[1]
# usage of a and b
I wrote the following R script:
list1 <- list(10, 20)
list2 <- list(30, 40)
mylist <- list(list1, list2)
for( j in 1:length(mylist))
{
print(j)
list1=mylist[[j]]
print(list1)
# Works perfect till here
# Error in below lines
a=list1[[0]]
b=list1[[1]]
# usage of a and b
}
In R, indexing starts from 1 and not 0 - difference between Python and R. So, if we change it to 1 and 2, it works. In addition, 1:length may be replaced with less buggy seq_along
for( j in seq_along(mylist)){
print(j)
list1 = mylist[[j]]
print(list1)
a=list1[[1]]
b=list1[[2]]
# usage of a and b
}
[1] 1
[[1]]
[1] 10
[[2]]
[1] 20
[1] 2
[[1]]
[1] 30
[[2]]
[1] 40
NOTE: list1, a, b are objects created within the loop and this gets updated in each iteration. It is not clear about the final outcome
A translation of your python code might be something like below
> for (lst in mylist) {
+ a <- lst[[1]]
+ b <- lst[[2]]
+ print(c(a, b))
+ }
[1] 10 20
[1] 30 40

Use paste0 to create multiple object names with a for loop

I would like to create multiple object names with a for loop. I have tried the following which fails horribly:
somevar_1 = c(1,2,3)
somevar_2 = c(4,5,6)
somevar_3 = c(7,8,9)
for (n in length(1:3)) {
x <- as.name(paste0("somevar_",[i]))
x[2]
}
The desired result is x being somevar_1, somevar_2, somevar_3 for the respective iterations, and x[2] being 2, 5 and 8 respectively.
How should I do this?
somevar_1 = c(1,2,3)
somevar_2 = c(4,5,6)
somevar_3 = c(7,8,9)
for (n in 1:3) {
x <- get(paste0("somevar_", n))
print(x[2])
}
Result
[1] 2
[1] 5
[1] 8
We can use mget to get all the required objects in a list and use sapply to subset 2nd element from each of them.
sapply(mget(paste0("somevar_", 1:3)), `[`, 2)
#somevar_1 somevar_2 somevar_3
# 2 5 8

How use match.call in a nested function

I tried to get the list of names and the expression in ... in a function composition. Let's suppose a function:
g <- function(...) {
print(as.list(match.call(expand.dots = FALSE))$...)
}
And if we call:
g(rnorm(5), par = "a", 4 + 4)
We get:
[[1]]
rnorm(5)
$par
[1] "a"
[[3]]
4 + 4
And it's nice: we can get the expression call for every argument and validate. But I need this but in a function composition:
f <- function(...) g(...)
f(rnorm(5), par = "a", 4 + 4)
But I get:
[[1]]
..1
$par
[1] "a"
[[3]]
..3
I'm reading some chapters http://adv-r.had.co.nz/Expressions.html but I can't find the solution yet. I know, I need kepp studying.
Any tips? Thanks in advance.
If you just want the parameters, you don't need the entire call. Just use substitute() to access the ... rather than match.call
g <- function(...) {
print(substitute(...()))
}
f <- function(...) g(...)
f(rnorm(5), par = "a", 4 + 4)
# [[1]]
# rnorm(5)
#
# $par
# [1] "a"
#
# [[3]]
# 4 + 4
There's also Hadley's recommendation of
g <- function(...) {
print( eval(substitute(alist(...))))
}

How do I extract arguments in a function (written as a string) in R?

Let suppose I have defined a function by f <- function(x,y,z) {...}.
I would like to be able to transform an expression calling that function into a list of the parameters called by that function; it is the opposite of the do.call function.
For example, let us say I have such a function f, and I also have a string "f(2,1,3)".
How can I transform the string "f(2,1,3)" into the list of the parameters list(x=1,y=2,z=3)?
After you've parsed your character string into an R expression, use match.call() to match supplied to formal arguments.
f <- function(x,y,z) {}
x <- "f(1,2,3)"
ee <- parse(text = x)[[1]]
cc <- match.call(match.fun(ee[[1]]), ee)
as.list(cc)[-1]
# $x
# [1] 1
#
# $y
# [1] 2
#
# $z
# [1] 3
Alternatively:
f <- function(x,y,z) {...}
s <- "f(x = 2, y = 1, z = 3)"
c <- as.list(str2lang(s))
c[-1]
# $x
# [1] 2
#
# $y
# [1] 1
#
# $z
# [1] 3
I was looking for a solution to this a while ago in order to reconstruct a function call from a string. Hopefully this will be of use to someone who is looking for a solution to a similar problem.

Mapping indices of vector elements

This is probably a trivial question.
Given a vector of characters, some of which are repeating:
vec <- c("a","b","d","e","e","f","g","a","d")
I'm looking for an efficient function that will return for each unique element in vec the indices of where it appears in vec.
I imagine that the return value would be something like this list:
list(a = c(1,8), b = 2, d = c(3,9), e = c(4,5), f = 6, g = 7)
Here's a few options:
lapply(setNames(unique(vec),unique(vec)), function(x) which(x == vec) )
# or to avoid setNames and still ensure you get a list:
sapply(unique(vec), function(x) which(x == vec), simplify=FALSE)
# or even better but maybe not as extensible:
split(seq_along(vec),vec)
All giving:
$a
[1] 1 8
$b
[1] 2
$d
[1] 3 9
$e
[1] 4 5
$f
[1] 6
$g
[1] 7

Resources