Reputation:
I am trying to write a function that inputs 2 vectors and returns a matrix where each element [i,j] is x[i]+y[j]
For example, let's say x is
2 3 5 7
And y is
2 3 8
The output needs to be
4 5 10 5 6 11 7 8 15 9 10 15
How can it be done by using one of the apply functions (in R) and without using loops?
Upvotes: 2
Views: 117
Reputation: 12935
BENCHMARK
SMALL scale
library(microbenchmark)
x <- c(2,3,5,7)
y <- c(2,3,8)
func_Stephan.Kolassa <- function(x, y){ as.vector(t(outer(x,y,"+"))) }
func_m0h3n <- function(x, y){as.vector(sapply(x, function(a) { sapply(y, function(b) a+b) }))}
func_jogo <- function(x, y){rep(x, each=length(y)) + y}
func_Vincent.Guillemot <- function(x, y){do.call("c", lapply(x, "+", y))}
r1=func_Stephan.Kolassa(x,y)
identical(func_m0h3n(x,y), r1)
# [1] TRUE
identical(func_jogo(x,y), r1)
# [1] TRUE
identical(func_Vincent.Guillemot(x,y), r1)
# [1] TRUE
microbenchmark(func_Stephan.Kolassa(x,y), func_m0h3n(x,y), func_jogo(x,y), func_Vincent.Guillemot(x,y))
Unit: nanoseconds
expr min lq mean median uq max neval
func_Stephan.Kolassa(x, y) 9315 9916 11875.10 10517.0 11118.0 52582 100
func_m0h3n(x, y) 53184 55587 59850.90 57089.5 63099.5 100958 100
func_jogo(x, y) 601 902 1307.46 1202.0 1203.0 8414 100
func_Vincent.Guillemot(x, y) 5409 6009 6836.19 6610.0 6911.5 17728 100
MEDIUM scale
library(microbenchmark)
set.seed(100)
x <- sample(500)
y <- sample(500)
func_Stephan.Kolassa <- function(x, y){ as.vector(t(outer(x,y,"+"))) }
func_m0h3n <- function(x, y){as.vector(sapply(x, function(a) { sapply(y, function(b) a+b) }))}
func_jogo <- function(x, y){rep(x, each=length(y)) + y}
func_Vincent.Guillemot <- function(x, y){do.call("c", lapply(x, "+", y))}
r1=func_Stephan.Kolassa(x,y)
identical(func_m0h3n(x,y), r1)
# [1] TRUE
identical(func_jogo(x,y), r1)
# [1] TRUE
identical(func_Vincent.Guillemot(x,y), r1)
# [1] TRUE
microbenchmark(func_Stephan.Kolassa(x,y), func_m0h3n(x,y), func_jogo(x,y), func_Vincent.Guillemot(x,y))
Unit: microseconds
expr min lq mean median uq max neval
func_Stephan.Kolassa(x, y) 1494.534 1593.389 1873.291 1695.699 1787.793 4138.064 100
func_m0h3n(x, y) 147586.916 156473.596 160685.272 159005.951 161304.842 218236.564 100
func_jogo(x, y) 3861.932 3889.275 4544.668 3988.130 4102.308 46668.592 100
func_Vincent.Guillemot(x, y) 926.047 1046.235 1648.450 1083.944 1173.934 43615.523 100
LARGE scale
library(microbenchmark)
set.seed(100)
x <- sample(2000)
y <- sample(2000)
func_Stephan.Kolassa <- function(x, y){ as.vector(t(outer(x,y,"+"))) }
func_m0h3n <- function(x, y){as.vector(sapply(x, function(a) { sapply(y, function(b) a+b) }))}
func_jogo <- function(x, y){rep(x, each=length(y)) + y}
func_Vincent.Guillemot <- function(x, y){do.call("c", lapply(x, "+", y))}
r1=func_Stephan.Kolassa(x,y)
identical(func_m0h3n(x,y), r1)
# [1] TRUE
identical(func_jogo(x,y), r1)
# [1] TRUE
identical(func_Vincent.Guillemot(x,y), r1)
# [1] TRUE
microbenchmark(func_Stephan.Kolassa(x,y), func_m0h3n(x,y), func_jogo(x,y), func_Vincent.Guillemot(x,y))
Unit: milliseconds
expr min lq mean median uq max neval
func_Stephan.Kolassa(x, y) 36.74259 43.74743 74.99681 83.46406 85.95180 136.20484 100
func_m0h3n(x, y) 2456.30410 2520.29204 2552.30450 2543.17729 2569.69776 2716.24160 100
func_jogo(x, y) 62.74701 63.20868 67.18512 64.66190 66.28563 117.96876 100
func_Vincent.Guillemot(x, y) 14.35702 16.37528 30.59328 18.03522 58.94261 65.50772 100
Upvotes: 2
Reputation: 3429
Just for the pleasure of using lapply
:
x <- c(2,3,5,7)
y <- c(2,3,8)
do.call("c", lapply(x, "+", y))
# [1] 4 5 10 5 6 11 7 8 13 9 10 15
Upvotes: 1
Reputation: 12935
Here is my solution:
as.vector(sapply(x, function(a) { sapply(y, function(b) a+b) }))
# [1] 4 5 10 5 6 11 7 8 13 9 10 15
Upvotes: 0
Reputation: 12569
This gives the desired result:
x <- c(2,3,5,7)
y <- c(2,3,8)
rep(x, each=length(y)) + y
# [1] 4 5 10 5 6 11 7 8 13 9 10 15
Upvotes: 2
Reputation: 8345
You need to use outer()
and convert the result to a matrix row-by-row by transposing it first using t()
:
> x <- c(2,3,5,7)
> y <- c(2,3,8)
> outer(x,y,"+")
[,1] [,2] [,3]
[1,] 4 5 10
[2,] 5 6 11
[3,] 7 8 13
[4,] 9 10 15
> as.vector(t(outer(x,y,"+")))
[1] 4 5 10 5 6 11 7 8 13 9 10 15
Upvotes: 5