Reputation: 69
We are given the following R code which iterates through every row and column of matrix A
, and if the value is positive, it saves it as is in matrix, and if it is negative, the calculate the exponential value minus 1.
qFunc1 <- function(A) {
if (!is.matrix(A) || !is.numeric(A))
stop("A must be numeric matrix")
B <- matrix(NA, nrow = nrow(A), ncol = ncol(A))
for (i in seq_len(nrow(A)))
{
for (j in seq_len(ncol(A)))
{
if (!is.na(A[i, j]))
{
if (A[i, j] > 0)
B[i, j] <- A[i, j]
else
B[i, j] <- exp(A[i, j]) - 1
}
}
}
B
}
This code gives the correct result but we are asked to "vectorize" the loop-nest with a one-liner, which I don't know how. The "if ... else ..." in another "if" makes me struggle.
Thanks for any help in advance!
Note that I am not allowed to use any *apply
functions as they are not "vectorized".
Upvotes: 1
Views: 68
Reputation: 73265
Without the one-liner requirement I would do
B <- A ## initialize the output matrix
ind <- (!is.na(A)) & (A <= 0) ## a logical matrix
B[ind] <- exp(A[ind]) - 1 ## update the output matrix
With the one-liner requirement I would do
B <- ifelse((!is.na(A)) & (A <= 0), exp(A) - 1, A)
Here is a quick test.
set.seed(0)
A <- round(matrix(rnorm(25), 5, 5), 2) ## create a 5 x 5 matrix
A[sample.int(length(A), 5)] <- NA ## set 5 NA
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1.26 NA 0.76 -0.41 -0.22
#[2,] -0.33 -0.93 NA 0.25 0.38
#[3,] 1.33 -0.29 -1.15 NA 0.13
#[4,] 1.27 -0.01 -0.29 0.44 0.80
#[5,] 0.41 NA -0.30 NA -0.06
## use your original function
B1 <- qFunc1(A)
## one-liner "vectorization"
B2 <- ifelse((!is.na(A)) & (A <= 0), exp(A) - 1, A)
## check that they give identical results
all.equal(B1, B2)
#[1] TRUE
Upvotes: 3