Why am I getting 46 errors with this for loop? - r

I am looking for all the even numbers from 1 through 100.
n <- seq(from = 1, to = 100)
for (x in n) {if(n %% 2 == 0) print(n)}

Here, we need 'x' instead of 'n' as 'n' is the whole vector
for(x in n) if(x %% 2 == 0) print(x)
data
n <- seq(from = 1, to = 100)

As Akrun has already pointed out, you needed x %% 2, not n %% 2... note I've use i
n <- 1:100
for(i in n){
if(i %% 2 == 0){
print(i)
}
}
However, if you want the even numbers in your sequence you could just use:
n[n %% 2 == 0]
Note also that you got warnings not errors, they're subtly different

Related

R: cumulative sum until certain value

I want to calculate how many values are taken until the cumulative reaches a certain value.
This is my vector: myvec = seq(0,1,0.1)
I started with coding the cumulative sum function:
cumsum_for <- function(x)
{
y = 1
for(i in 2:length(x)) # pardon the case where x is of length 1 or 0
{x[i] = x[i-1] + x[i]
y = y+1}
return(y)
}
Now, with the limit
cumsum_for <- function(x, limit)
{
y = 1
for(i in 2:length(x)) # pardon the case where x is of length 1 or 0
{x[i] = x[i-1] + x[i]
if(x >= limit) break
y = y+1}
return(y)
}
which unfortunately errors:
myvec = seq(0,1,0.1)
cumsum_for(myvec, 0.9)
[1] 10
Warning messages:
1: In if (x >= limit) break :
the condition has length > 1 and only the first element will be used
[...]
What about this? You can use cumsum to compute the cumulative sum, and then count the number of values that are below a certain threshold n:
f <- function(x, n) sum(cumsum(x) <= n)
f(myvec, 4)
#[1] 9
f(myvec, 1.1)
#[1] 5
You can put a while loop in a function. This stops further calculation of the cumsum if the limit is reached.
cslim <- function(v, l) {
s <- 0
i <- 0L
while (s < l) {
i <- i + 1
s <- sum(v[1:i])
}
i - 1
}
cslim(v, .9)
# [1] 4
Especially useful for longer vectors, e.g.
v <- seq(0, 3e7, 0.1)

What is the purpose of b <-c() in this code?

I have written a code to find a positive integer that has more divisors than any smaller positive integer has. My code is right but I noticed that I wrote a step only because I had solved other questions similarly but I don't really understand the intuition of why we write this particular line:
b <- c()
Also, why is there a "b" in c(b, sum..) as in the below line:
b <- c(b, sum(p %% c(1:p) == 0))
Here is the full code:
code <- function(n) {
if (n < 1 | n %% 1 != 0)
print("Only positive integers allowed")
else if (n <= 2)
return(TRUE)
else {
a <- sum(n %% c(1:n) == 0)
b <- c()
for (p in 1:(n-1)) {
b <- c(b, sum(p %% c(1:p) == 0))
}
return(max(b) < a)
}
}
code(8)
code(6)
code(-7)
As already explained in comments the purpose of b<-c() is to initialise an empty vector and fill it in the loop. Also the reason why you are using b <- c(b,sum(p%%c(1:p)== 0)) is to append new values to already existing values of b.
For example,
b <- c()
b
#NULL
b <- c(b, 1)
b
#[1] 1
b <- c(b, 2)
b
#[1] 1 2
Usually, it is not a good practice to grow an object in a loop, it is highly inefficient to do that. If the size of output is fixed you can initialise a vector with fixed size and then fill it in the loop.
code <- function(n){
if (n<1 | n%%1!=0)
print("Only positive integers allowed")
else if (n <= 2)
return(TRUE)
else{
a <- sum(n%%c(1:n) == 0)
b <- integer(n-1) #Creates a vector with 0's of length n-1
for (p in 1:(n-1)) {
b[p] <- sum(p%%c(1:p)== 0)
}
return(max(b) < a)
}
}
Or in this case you can save only the max value of b since all other values are not important.
code <- function(n){
if (n<1 | n%%1!=0)
print("Only positive integers allowed")
else if (n <= 2)
return(TRUE)
else{
a <- sum(n%%c(1:n) == 0)
max_b <- 0
for (p in 1:(n-1)) {
val <- sum(p%%c(1:p)== 0)
if(val > max_b) max_b <- val
}
return(max_b < a)
}
}

Calculating a range (100:1000) of Fibonacci numbers using the repeat-loop in R

When trying to find a code to calculate how many Fibonacci numbers are in the range between 100 and 1000, I tried using the repeat loop as seen below, but I am very unsure where to insert the specifications for the range (100:1000) and what I tried does certainly not work.
I know that the part with head(x, -1) < 1000 is not correct - how could I fix the code?
x <- c(0, 1)
repeat {
x <- c(x, sum(tail(x, 2)))
if(tail(x, 1) > 100) {
x <- head(x, -1) < 1000
break
}
}
print(x)
I guess you can try the code below, where you jump out of the loop when the newly generated item is not smaller than 1000
x <- c(0, 1)
repeat {
if ((v <- sum(tail(x, 2))) >= 1000) break
x <- c(x, v)
}
x[x >= 100]
which gives
> x[x >= 100]
[1] 144 233 377 610 987

How to apply a function to a matrix in R

Write a function which takes a matrix that can be coerces into a matrix; the function should return a matrix which is the same as the function argument, but every even number is not changed and odd number is doubled.
I'm very new to R. Can someone help me complete my codes:
mx = matrix(c(1,1,3,5,2,6,-2,-1,-3), nrow = 3, byrow = TRUE)
fun = function(mx){
for(i in mx){
if(i %% 2 == 0){
return(i)
}
else if(i %% 2 > 0){
return(2*i)
}
}
}
Don't need a function, just use the built-in function ifelse:
mx <- ifelse(mx %% 2 == 0, mx, 2*mx)
Or, if you prefer to encapsulate it into a function:
fun = function(mx) {
ifelse(mx %% 2 == 0, mx, 2*mx)
}
res <- fun(mx)
## [,1] [,2] [,3]
##[1,] 2 2 6
##[2,] 10 2 6
##[3,] -2 -2 -6
Explanation:
ifelse performs a vectorized comparison over all elements of the matrix mx to see if each element is even (i.e., mx %% 2 == 0). For each element if this comparison condition is TRUE, the next argument is returned, which in this case is just the value from that element in mx. Otherwise, the last argument is returned, which is 2 times the value from that element in mx as you wish.
That's easy using indices :)
double_odd <- function(mx){
odds_idx <- (mx %% 2 != 0)
mx[odds_idx] <- 2 * mx[odds_idx]
mx # If it is the last statement, you don't need return
}
Cheers
Using your try:
fun = function(mx){
res <- matrix(data = NA, ncol = ncol(mx), nrow = nrow(mx))
for(i in 1:ncol(mx)){
for(j in 1:nrow(mx))
if(mx[j, i] %% 2 == 0){
res[j, i] <- mx[j, i]
}else{
res[j, i] <- 2 * mx[j, i]
}
}
return(res)
}
of course not the most elegant solution :)

Euler Project #1 in R

Problem
Find the sum of all numbers below 1000 that can be divisible by 3 or 5
One solution I created:
x <- c(1:999)
values <- x[x %% 3 == 0 | x %% 5 == 0]
sum(values
Second solution I can't get to work and need help with. I've pasted it below.
I'm trying to use a loop (here, I use while() and after this I'll try for()). I am still struggling with keeping references to indexes (locations in a vector) separate from values/observations within vectors. Loops seem to make it more challenging for me to distinguish the two.
Why does this not produce the answer to Euler #1?
x <- 0
i <- 1
while (i < 100) {
if (i %% 3 == 0 | i %% 5 == 0) {
x[i] <- c(x, i)
}
i <- i + 1
}
sum(x)
And in words, line by line this is what I understand is happening:
x gets value 0
i gets value 1
while object i's value (not the index #) is < 1000
if is divisible by 3 or 5
add that number i to the vector x
add 1 to i in order (in order to keep the loop going to defined limit of 1e3
sum all items in vector x
I am guessing x[i] <- c(x, i) is not the right way to add an element to vector x. How do I fix this and what else is not accurate?
First, your loop runs until i < 100, not i < 1000.
Second, replace x[i] <- c(x, i) with x <- c(x, i) to add an element to the vector.
Here is a shortcut that performs this sum, which is probably more in the spirit of the problem:
3*(333*334/2) + 5*(199*200/2) - 15*(66*67/2)
## [1] 233168
Here's why this works:
In the set of integers [1,999] there are:
333 values that are divisible by 3. Their sum is 3*sum(1:333) or 3*(333*334/2).
199 values that are divisible by 5. Their sum is 5*sum(1:199) or 5*(199*200/2).
Adding these up gives a number that is too high by their intersection, which are the values that are divisible by 15. There are 66 such values, and their sum is 15*(1:66) or 15*(66*67/2)
As a function of N, this can be written:
f <- function(N) {
threes <- floor(N/3)
fives <- floor(N/5)
fifteens <- floor(N/15)
3*(threes*(threes+1)/2) + 5*(fives*(fives+1)/2) - 15*(fifteens*(fifteens+1)/2)
}
Giving:
f(999)
## [1] 233168
f(99)
## [1] 2318
And another way:
x <- 1:999
sum(which(x%%5==0 | x%%3==0))
# [1] 233168
A very efficient approach is the following:
div_sum <- function(x, n) {
# calculates the double of the sum of all integers from 1 to n
# that are divisible by x
max_num <- n %/% x
(x * (max_num + 1) * max_num)
}
n <- 999
a <- 3
b <- 5
(div_sum(a, n) + div_sum(b, n) - div_sum(a * b, n)) / 2
In contrast, a very short code is the following:
x=1:999
sum(x[!x%%3|!x%%5])
Here is an alternative that I think gives the same answer (using 99 instead of 999 as the upper bound):
iters <- 100
x <- rep(0, iters-1)
i <- 1
while (i < iters) {
if (i %% 3 == 0 | i %% 5 == 0) {
x[i] <- i
}
i <- i + 1
}
sum(x)
# [1] 2318
Here is the for-loop mentioned in the original post:
iters <- 99
x <- rep(0, iters)
i <- 1
for (i in 1:iters) {
if (i %% 3 == 0 | i %% 5 == 0) {
x[i] <- i
}
i <- i + 1
}
sum(x)
# [1] 2318

Resources