When i run the below function, i get the output for just one value. with a message, \"the condition has length > 1 and only the first element will be used\"
What cha
The other way to vectorize this function is to use ifelse
instead of if
:
ownsquare2 <- function(n)
{
for (i in seq(from = 1, to = 506, by = 0.001))
{
r <- i * i
x <- ifelse(r <= n, i, x)
}
x
}
ownsquare2(1:10)
## [1] 1.000 1.414 1.732 2.000 2.236 2.449 2.645 2.828 3.000 3.162
Here, x
is treated as a vector in the function, and the substitution used in the if
expression is vectorized with ifelse
.
The translation from if
to ifelse
is fairly straightforward, but becomes unreadable (IMO) for chained if-else code.
You are trying to create a function that can do the same operation on multiple values, returning a vector of equal length as its argument. In R parlance that behavior of a function is known as "vectorization". And there is a wrapper function around the mapply
function that is named Vectorize
. This illustrates its use with your function which does work correctly on a single element:
Vownsquare <- Vectorize(ownsquare)
Vownsquare( 1:10 )
#-------
[1] 1.000 1.414 1.732 2.000 2.236 2.449 2.645 2.828 3.000 3.162
It's really slow, but this is the result of an inefficient implementation. Might improve your efficiency by learning to use break
. This avoids the unnecessary iteration after the condition r>n is reached.
ownsquare <- function(n)
{
for (i in seq(from = 1, to = 506, by = 0.001))
{
r <- i * i
if (r > n) { x=i; break() }
}
x
}
Vownsquare <- Vectorize(ownsquare)
Vownsquare( 1:10 )
[1] 1.001 1.415 1.733 2.001 2.237 2.450 2.646 2.829 3.001 3.163
Notice this comparison of Lundberg's implementation that computes the full 506,000 length vector for each argument:
system.time(ownsquare2(1:10)) # makes full vectors
user system elapsed
7.311 0.069 7.292
system.time(ownsquare(1:10)) # uses break
user system elapsed
0.008 0.000 0.008
system.time(Vownsquareoriginal( 1:10 )) # full vectors with if()
user system elapsed
3.746 0.040 3.729