I was prompted a question and am ever so close to solving what I need. The question is as follows-
"Write a while loop that computes and stores as a new object, the factorial of any non-negative integer mynum by decrementing mynum by 1 at each repetition of the braced code."
Another factor was that if 0 or 1 was entered, the output would be 1.
The code that I wrote as follows-
factorialcalc <- function(i){
factorial <- 1
if(i==0 | i==1){
factorial <- 1
} else{
while(i >= 1){
factorial <- factorial * i
i <- i-1
}
}
return (factorial)
}
with inputs-
mynum <- 5
factorialcalc(mynum)
and output-
[1] 120
You may be wondering, "your code works perfect, so what's the issue?"
My issue lies in the part of the question that says "computes AND stores."
How can I modify my code to put the answers of factorialcalc into a vector?
Example-
I input
mynum <- 5
factorialcalc(mynum)
and
mynum <- 3
factorialcalc(mynum)
and
mynum <- 4
factorialcalc(mynum)
When I call this new vector, I would like to see a vector with all three of their outputs
(so almost like I made a vector c(120,6,24))
I'm thinking there's a way to add this vector somewhere in my function or while loop, but I'm not sure where. Also, please note that the answer must contain a loop like in my code.
Option 1.
"Vectorize" your function
# simply wrap the whole thing in Vectorize()
Factorialcalc = Vectorize(function(i){
factorial <- 1
if(i==0 | i==1){
factorial <- 1
} else{
while(i >= 1){
factorial <- factorial * i
i <- i-1
}
}
return (factorial)
})
# Now when you supply it a vector, it runs on each element
> Factorialcalc(c(5, 3, 4))
[1] 120 6 24
Option 2.
Use functions that are designed to apply a single function to multiple elements of a supplied vector.
Using map_dbl from the purrr package, you can call:
map_dbl(c(5, 3, 4), factorialcalc)
Which supplies to your function factorialcalc each element in vector and concatenates each result before returning a vector.
Using base R you can simply use the apply-family functions:
sapply(c(5, 3, 4), factorialcalc)
and get the same result.
Example
> map_dbl(c(5, 3, 4), factorialcalc)
[1] 120 6 24
> sapply(c(5, 3, 4), factorialcalc)
[1] 120 6 24
Related
I want to create a function that transforms its object.
I have tried to transform the variable as you would normally, but within the function.
This works:
vec <- c(1, 2, 3, 3)
vec <- (-1*vec)+1+max(vec, na.rm = T)
[1] 3 2 1 1
This doesn't work:
vec <- c(1, 2, 3, 3)
func <- function(x){
x <- (-1*x)+1+max(x, na.rm = T))
}
func(vec)
vec
[1] 1 2 3 3
R is functional so normally one returns the output. If you want to change
the value of the input variable to take on the output value then it is normally done by the caller, not within the function. Using func from the question it would normally be done like this:
vec <- func(vec)
Furthermore, while you can overwrite variables it is, in general, not a good
idea. It makes debugging difficult. Is the current value of vec the
input or output and if it is the output what is the value of the input? We
don't know since we have overwritten it.
func_ovewrite
That said if you really want to do this despite the comments above then:
# works but not recommended
func_overwrite <- function(x) eval.parent(substitute({
x <- (-1*x)+1+max(x, na.rm = TRUE)
}))
# test
v <- c(1, 2, 3, 3)
func_overwrite(v)
v
## [1] 3 2 1 1
Replacement functions
Despite R's functional nature it actually does provide one facility for overwriting although the function in the question is not really a good candidate for it so let us change the example to provide a function incr which increments the input variable by a given value. That is, it does this:
x <- x + b
We can write this in R as:
`incr<-` <- function(x, value) x + value
# test
xx <- 3
incr(xx) <- 10
xx
## [1] 13
T vs. TRUE
One other comment. Do not use T for true. Always write it out. TRUE is a reserved name in R but T is a valid variable name so it can lead to hard to find errors such as when someone uses T for temperature.
I have just started learning R and I wrote this code to learn on functions and loops.
squared<-function(x){
m<-c()
for(i in 1:x){
y<-i*i
c(m,y)
}
return (m)
}
squared(5)
NULL
Why does this return NULL. I want i*i values to append to the end of mand return a vector. Can someone please point out whats wrong with this code.
You haven't put anything inside m <- c() in your loop since you did not use an assignment. You are getting the following -
m <- c()
m
# NULL
You can change the function to return the desired values by assigning m in the loop.
squared <- function(x) {
m <- c()
for(i in 1:x) {
y <- i * i
m <- c(m, y)
}
return(m)
}
squared(5)
# [1] 1 4 9 16 25
But this is inefficient because we know the length of the resulting vector will be 5 (or x). So we want to allocate the memory first before looping. This will be the better way to use the for() loop.
squared <- function(x) {
m <- vector("integer", x)
for(i in seq_len(x)) {
m[i] <- i * i
}
m
}
squared(5)
# [1] 1 4 9 16 25
Also notice that I have removed return() from the second function. It is not necessary there, so it can be removed. It's a matter of personal preference to leave it in this situation. Sometimes it will be necessary, like in if() statements for example.
I know the question is about looping, but I also must mention that this can be done more efficiently with seven characters using the primitive ^, like this
(1:5)^2
# [1] 1 4 9 16 25
^ is a primitive function, which means the code is written entirely in C and will be the most efficient of these three methods
`^`
# function (e1, e2) .Primitive("^")
Here's a general approach:
# Create empty vector
vec <- c()
for(i in 1:10){
# Inside the loop, make one or elements to add to vector
new_elements <- i * 3
# Use 'c' to combine the existing vector with the new_elements
vec <- c(vec, new_elements)
}
vec
# [1] 3 6 9 12 15 18 21 24 27 30
If you happen to run out of memory (e.g. if your loop has a lot of iterations or vectors are large), you can try vector preallocation which will be more efficient. That's not usually necessary unless your vectors are particularly large though.
Let's say I want to multiply each even element of a vector by 2 and each odd element of a vector by 3. Here is some code that can do this:
v <- 0:10
idx <- v %% 2 == 0
v[idx] <- v[idx] * 2
v[!idx] <- v[!idx] * 3
This would get difficult if I had more than two cases. It seems like the apply family of functions never deals with vectors so I don't know a better way to do this problem. Maybe using an apply function would work if I made transformations on the data, but it seems like that shouldn't be something that I would need to do to solve this simple problem.
Any ideas?
Edit: Sorry for the confusion. I am not specifically interested in the "%%" operator. I wanted to put some concrete code in my question, but, based on the responses to the question, was too specific. I wanted to figure out how to apply some arbitrary function to each member of the list. This was not possible with apply() and I thought sapply() only worked with lists.
You can do:
v <- v * c(2, 3)[v %% 2 + 1]
It is generalizable to any v %% n, e.g.:
v <- v * c(2, 3, 9, 1)[v %% 4 + 1]
Also it does not require that length(v) be a multiple of n.
You can use vector multiplication to do what you want:
tmp <- 1:10
tmp * rep(c(3,2), length(tmp)/2)
This is easy to extend to three or more cases:
tmp * rep(c(3,2,4), length(tmp)/3)
Easiest would be:
v*c(2,3) # as suggested by flodel in a comment.
The term to search for in the documentation is "argument recycling" ... a feature of the R language. Only works for dyadic infix functions (see ?Ops). For non-dyadcic vectorized functions that would not error out with some of the arguments and where you couldn't depend on the structure of "v" to be quite so regular, you could use ifelse:
ifelse( (1:length(v)) %% 2 == 0, func1(v), func2(v) )
This constructs two vectors and then chooses elements in the first or second based on the truth value of hte first argument. If you were trying to answer the question in the title of your posting then you should look at:
?sapply
Here is an answer allowing any set of arbitrary functions to be applied to defined groups within a vector.
# source data
test <- 1:9
# categorisations of source data
cattest <- rep(1:3,each=3)
#[1] 1 1 1 2 2 2 3 3 3
Make the function to differentially apply functions:
categ <- function(x,catg) {
mapply(
function(a,b) {
switch(b,
a * 2,
a * 3,
a / 2
)
},
x,
catg
)
}
# where cattest = 1, multiply by 2
# where cattest = 2, multiply by 3
# where cattest = 3, divide by 2
The result:
categ(test,cattest)
#[1] 2.0 4.0 6.0 12.0 15.0 18.0 3.5 4.0 4.5
I would like to create a numeric vector with the results of a loop such as
> for (i in 1:5) print(i+1)
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
It seems strange that the same expression without 'print' returns nothing
> for (i in 1:5) i+1
>
Does anyone have an explanation/solution?
This is standard behaiviour -- when you say you want to create a numeric vector,
print will not do that
The expression in a for loop is an argument to the primitive function for
From ?`for` in the value section
for, while and repeat return NULL invisibly. for sets var to the last
used element of seq, or to NULL if it was of length zero.
print prints the results to the console.
for(i in 1:5) i + 1
merely calculates i + 1 for each iteration and returns nothing
If you want to assign something then assign it using <-, or less advisably assign
You can avoid an explicit loops by using sapply. This (should) avoid any pitfalls of growing vectors
results <- sapply(1:5, function(i) { i + 1})
Now frankly, there must be a better solution than this
loopee <- function(x){
res <- vector(mode = "numeric", length(x))
for (i in 1:x) {res[i] <- i+1}
return(res)}
> loopee(5)
[1] 2 3 4 5 6
I want to write a function that, given a vector v computes the product of all the entries in v. (There is a function in R that does this, but I want to write one myself.)
I tried however how can I get for product of any elements in a vector?
product <- function(v){
out <- 1
for(i in 1:length(v)){
out <- out*v[i]
}
out
}
If you use ... as the argument to your function, you can pass it several objects or just one. Inside the function, you can convert to a list and use Reduce to apply a function (*) recursively to the list. If you combine list, unlist and as.list you can make this very general. The following will work with a vector, or with 2 or more numbers, or a mixture of vectors and single numbers.
> product <- function(...) Reduce("*", as.list(unlist(list(...))))
> product(2, 7, 3)
[1] 42
> product(c(2, 7, 3))
[1] 42
> product(2, c(7, 3))
[1] 42
The use of Recall for tail recursion:
prd2 <- function(x)
if(length(x) == 2) { x[1] *x[-1] } else x[1] * Recall(x[-1])
prd2(c(2,3,4))
#[1] 24