Objective: write a for loop and understand it focuses on the iteration and not actions
being lazy, instead of you doing the work, rely on the work of someone else | Hadley Wickham

c(1, 2, 3, 4) to the function odd_count should output:odd_count(c(1, 2, 3, 4))
## [1] 2
if, else if, else or a for loop.start by writing a piece of code that does the job, following the steps of your pseudocode
# test vector named a
a <- c(1, 2, 3, 4)
# initialized a scalar at 0
counter <- 0
# iterate through the values of a
for (i in a) {
# if integer division by is not zero
if (i %% 2 != 0) {
# increment the counter by 1
counter <- counter + 1
}
}
# how much is counter?
counter
## [1] 2
Convert your functional piece of code as a function named odd_count()
a %% b in R and returns the reminder of the division of a/b. If b = 2 and the result is different from zero, then a is an odd number.a equals b using == and not =. a = b is an assignment leading a to take the value of b!a <- c(1, 2, 3, 4)
odd_count <- function(x) {
counter <- 0
for (i in x) {
if (i %% 2 != 0) {
counter <- counter + 1
}
}
return(counter)
}
odd_count(c(a))
## [1] 2
What would happen if we provide some characters, or a matrix, as an input to odd_count()? Is your function able to deal with such an input?
No, but it should. Add a test before doing anything else to check if numbers are provided to the function.
stop("Warning! some conditions are not fulfilled to continue bla bla \n") should help. It stops the execution and print the chosen message
a <- c(1, 2, 3, 4)
odd_count <- function(x) {
# if the input is not numeric, we stop the code execution
# of note, the call. = FALSE is to avoid printing the code line, makes the error more explicit
if (!is.numeric(x)) stop("input not numeric!", call. = FALSE)
counter <- 0
for (i in x) {
if (i %% 2 != 0) {
counter <- counter + 1
}
}
return(counter)
}
odd_count(c(a, "a"))
## Error: input not numeric!
Now we would like to count only unique numbers that are odd. Change the function so that it takes a second argument uniq changing this behaviour: a boolean (TRUE/FALSE).
When set to TRUE, only unique numbers should be considered (see the function unique()). When set to FALSE (which we would like to be the default value), the result should be equal to version 2.
Please check that your 3 versions have the expected behaviour using the following table:
| input | version 1 | version 2 | version 3 (unique = TRUE) |
|---|---|---|---|
| c(0, 1) | 1 | 1 | 1 |
| c(0, 1, 2, ‘A’) | nasty error | input not numeric! | input not numeric! |
| c(0, 1, 2, 3, 5) | 3 | 3 | 3 |
| c(0, 1, 2, 3, 5, 3) | 4 | 4 | 3 |
a <- c(1, 2, 3, 4)
odd_count <- function(x, uniq = TRUE) {
if (!is.numeric(x)) stop("input not numeric!", call. = FALSE)
counter <- 0
if (uniq) x <- unique(x)
for (i in x) {
if (i %% 2 != 0) {
counter <- counter + 1
}
}
return(counter)
}
odd_count(c(a, 3), uniq = FALSE)
## [1] 3
odd_count(c(a, 3), uniq = TRUE)
## [1] 2
odd_count(c(a, 3))
## [1] 2
Now that the for loop was a pain to set-up, we can use what R is good at: vectorization
a <- c(1, 2, 3, 4)
odd_count <- function(x, uniq = TRUE) {
if (!is.numeric(x)) stop("input not numeric!", call. = FALSE)
if (uniq) x <- unique(x)
# the vector is integer divided by 2, the iteration is transparent
# then logical test: is different from 0
# finally sum up the logical vector, TRUE is 1, FALSE is 0
sum(x %% 2 != 0)
}
odd_count(c(a, 3), uniq = FALSE)
## [1] 3
odd_count(c(a, 3))
## [1] 2