Let’s try using a loop first. A preliminary idea is as follows: 1.
Construct a result vector result 2. Loop through the input
v - if v[i] does not equal
target, add it to result - otherwise, do not
add it to result (do nothing) 3. Return
result
Here is this idea implemented:
remove_elt <- function(v, target) {
result <- numeric(0)
for (i in seq_along(v)) {
if(v[i] != target) {
result <- c(result, v[i])
}
}
return(result)
}
remove_elt(c(14, 14, 7, 7, 14, 10), 14)
## [1] 7 7 10
Instead of a loop, we can do a vectorized comparison and
then filter for the desired values of v.
remove_elt <- function(v, target) {
v[v != target]
}
remove_elt(c(14, 14, 7, 7, 14, 10), 14)
## [1] 7 7 10
In the above, v != target is a vector of logicals which
we use to subset v itself. Please make sure you are
comfortable with this operation.
The first approach is clever: just print a matrix.
print_square <- function(n) {
m <- matrix("*", nrow = n, ncol = n)
print(m)
}
print_square(5)
## [,1] [,2] [,3] [,4] [,5]
## [1,] "*" "*" "*" "*" "*"
## [2,] "*" "*" "*" "*" "*"
## [3,] "*" "*" "*" "*" "*"
## [4,] "*" "*" "*" "*" "*"
## [5,] "*" "*" "*" "*" "*"
Think about how recycling occurs so that a single
* becomes n^2 *s.
Let’s build a vector of n *s and then use a
loop to print it n times.
print_square <- function(n) {
asts <- rep("*", n)
for (i in seq_len(n)) {
print(asts)
}
}
print_square(4)
## [1] "*" "*" "*" "*"
## [1] "*" "*" "*" "*"
## [1] "*" "*" "*" "*"
## [1] "*" "*" "*" "*"
A matrix approach is less straightforward in this case. But we can easily adapt the above loop. Now, the number of asterisks depends on the loop index.
print_triangle <- function(n) {
for (i in seq_len(n)) {
asts <- rep("*", i)
print(asts)
}
}
print_triangle(4)
## [1] "*"
## [1] "*" "*"
## [1] "*" "*" "*"
## [1] "*" "*" "*" "*"
We want to compare nums1 and nums2
element-wise, so it makes sense to loop over them. The vectors are
guaranteed to be of length n, so we can use this.
max_vec <- function(nums1, nums2, n) {
result <- vector(length = n) # this initializes an "empty" vector with length n
for (i in seq_len(n)) {
if (nums1[i] < nums2[i]) {
result[i] <- nums2[i] # Since nums2[i] is larger, place it into the result
} else {
result[i] <- nums1[i] # Since nums1[i] is larger, place it into the result
}
# Note that if they are equal, it does not matter which we put in.
}
return(result)
}
max_vec(1:4, c(0, 27, -5, 19), 4)
## [1] 1 27 3 19
It is always good to check if R already implements some basic
operation. In this case, max(a, b) returns the larger of
a and b.
max_vec <- function(nums1, nums2, n) {
result <- vector(length = n)
for (i in seq_len(n)) {
result[i] <- max(nums1[i], nums2[i]) # use the builtin max function
}
return(result)
}
max_vec(1:4, c(0, 27, -5, 19), 4)
## [1] 1 27 3 19
The above saves us from explicitly writing a branch.
A even better way is to use Google to find the
pmax function, which does everything for us.
pmax(1:4, c(0, 27, -5, 19))
## [1] 1 27 3 19
It is possible to do this with a loop. But let’s use a vectorized approach:
small_count_simple <- function(v, target) {
sum(v < target)
}
small_count_simple(c(10, 15, -2, 5), 11)
## [1] 3
v < target results in a logical vector. Summing up
the result gives the number of TRUE elements.
Loop over a result vector and fill in the values using
the approach from the previous problem.
small_count <- function(v) {
result <- vector(length = length(v))
for (i in seq_along(v)) {
result[i] <- sum(v < v[i])
}
return(result)
small_count(c(12, 100, -3, -12))
}
For this problem, we must be able to enumerate pairs of indices going
from 1 to length(v). In other words, if
v has 4 elements, we need to check the following pairs:
(i, j) <= (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)
Then if we look at v[i] + v[j], we will see the sum of
all pairs of elements of v. Think: why were
(2, 1), (4, 2), ... not included?
The idea is to use two loops: i going from 1 to
length(v) and j going from 1 to
i-1. This ensures we go over each pair exactly once
(why?).
two_sum <- function(v, target) {
i <- 0
j <- 0
for (i in seq_along(v)) {
for (j in seq_len(i-1)) {
if (v[i] + v[j] == target) {
return(c(i, j))
}
}
}
}
two_sum(c(2, 7, 11, 15), 9)
## [1] 2 1
The expression (v %% 2) == 0 gives a vector of logicals
indicating TRUE if the entry of v is even and FALSE
otherwise. Calling which on this logical vector gives all
the indices of TRUE, which are all the indices of even numbers of
v. Then index with [1] to find the first such
index.
first_even <- function(v) {
w_idx <- which((v %% 2) == 0)[1]
v[w_idx]
}
first_even(c(-1, -4, 0, 2))
## [1] -4
It may be clearer to do the indexing after subsetting
v: Below, w_idx is now a vector of
indices, which we use to subset v.
first_even <- function(v) {
w_idx <- which((v %% 2) == 0)
(v[w_idx])[1]
}
first_even(c(-1, -4, 0, 2))
## [1] -4
This is an exercise; please do this on your own. If you are stuck, talk to me.
This is also an exercise; please do this on your own. If you are stuck, talk to me.