Zero trip R for loop - r

The R code
n = 0
for (i in 1:n) {
cat("\nhello")
}
prints hello once, which is also the output when n = 1. What is the idiomatic way to write a loop whose body is not executed if n = 0?

You should use seq_len
n = 0
for (i in seq_len(n)) {
cat("\nhello")
}

We need seq_along (if it is a sequence) or seq_len (if it is a single value)
n <- 0
for(i in seq_len(n))
cat("\nhello")
The case when seq_along should be used when we expect the vector/list etc to have length more than 1
> n1 <- c(5, 3, 5)
> seq_len(n1)
[1] 1 2 3 4 5
Warning message:
In seq_len(n1) : first element used of 'length.out' argument
> seq_along(n1)
[1] 1 2 3
Other case when we have a length of 0
> n1 <- integer(0)
> # n1 <- NULL
> n1
integer(0)
> seq_along(n1)
integer(0)
> seq_len(n1)
Error in seq_len(n1) : argument must be coercible to non-negative integer
In addition: Warning message:
In seq_len(n1) : first element used of 'length.out' argument
Thus, there is no perfect solution that works for all cases. It may depend upon the input

Related

Vector of elements not being updated within loop

logically this code should make sense, I'm primarily a python programmer but I'm unsure why this is not working. It is not returning any errors. What I want is for this vector of primarily zeros to be changed to a vector of only 1's and -1's (hence using the sample function). My issue is that the values of the vector are not being updated, they are just staying as 0 and I'm not sure why.
Y = numeric(100)
for (i in 100){
x <- sample(1:2, 1)
if (x == 2){
Y[i] = 1
}
else{
Y[i] = -1
}
}
I've also changed the Y[i] = 1 to Y[i] <- 1 but this has not helped. I also know that x is either 1 or 2 because I test it manually using x == 2...etc
The only other issue I could think of is that x is an integer while the numbers sample returns are not but per checking this: (Note that x = 2L after the loop exited)
> typeof(x)
[1] "integer"
> typeof(2)
[1] "double"
> x == 2
[1] TRUE
I don't think it is the problem.
Any suggestions?
Because the loop is just run once i.e. the last iteration. It did change in the output vector Y
tail(Y)
#[1] 0 0 0 0 0 -1
Instead it would be 1:100
for(i in 1:100)
The second issue raised is with the typeof 'x'. Here, we are sampleing an integer with 1:2 instead of a numeric vector and that returns the same type as the input. According to ?':'
For numeric arguments, a numeric vector. This will be of type integer if from is integer-valued and the result is representable in the R integer type, otherwise of type "double"
typeof(1:2)
#[1] "integer"
typeof(c(1, 2))
#[1] "double"
Another option if it is a range (:) is to wrap with as.numeric
for (i in 1:100){
x <- sample(as.numeric(1:2), 1)
if (x == 2){
Y[i] = 1
}
else{
Y[i] = -1
}
}
check the type
typeof(Y)
#[1] "double"
typeof(x)
#[1] "double"
Also, R is a vectorized language so this:
x<-sample(1:2, 100, replace = TRUE)
Y<-ifelse(x==2, 1, -1)
will run about 1000 times faster than your loop.

FOR loop in R; not getting what I want

Just a general question:
When I run:
ok<-NULL
for (i in 1:3) {
ok[i]=i^2
i=i+1
}
The loop works (as expected).
> ok
[1] 1 4 9
Now when I try to do something like:
ok<-NULL
for (i in 1:3) {
ok[i]=i^2
x[i]<-ok[i]+1
y[i]<-cbind(ok[i],x)
i=i+1
}
And I want:
y = 1
2
4
5
9
10
Instead I get:
Warning messages:
1: In y[i] <- rbind(ok[i], x) :
number of items to replace is not a multiple of replacement length
2: In y[i] <- rbind(ok[i], x) :
number of items to replace is not a multiple of replacement length
3: In y[i] <- rbind(ok[i], x) :
number of items to replace is not a multiple of replacement length
4: In y[i] <- rbind(ok[i], x) :
number of items to replace is not a multiple of replacement length
5: In y[i] <- rbind(ok[i], x) :
number of items to replace is not a multiple of replacement length
Thanks in advance.
You should read up on R basics before starting to program.
You don't have to increment i in the loop (actually its quite confusing).
You don't cbind or rbind vectors this is for data.frame columns and rows.
y <- NULL
for(i in 1:3){ ok <- i^2; x <- ok + 1; y <- c(y, ok, x) }
or:
as.vector(sapply(1:3, function(i){ ok <- i^2; x <- ok + 1; c(ok, x) }))
With this command y[i]<-cbind(ok[i],x) you attempt to replace one element in the vector with several. This causes an error.
If you want to to get 1:3 squared, you would use:
ok <- (1:3)^2
ok
# [1] 1 4 9
If you want to get 1:3 squared, along with the numbers right after them, you might try:
as.vector(rbind(ok, ok+1))
[1] 1 2 4 5 9 10
for loops in R are often the wrong solution to your problem.

Select a column of matrix in r by looping

I have a matrix:
mvn.var=matrix(c(3,1,1,4,6,7,8,9),4,2,byrow=T)
And I try
for (i in 1:dim(mvn.var)[2]) {
y[i]=mvn.var[,i]
}
Because I want to have vectors y[i] where y[i] is a vector that consists of the elements of the i-th column of the previous mvn.var matrix.
I get:
Warning messages:
1: In y[i] = mvn.var[, i] :
number of items to replace is not a multiple of replacement length
2: In y[i] = mvn.var[, i] :
number of items to replace is not a multiple of replacement length
You are trying to assign to an element of the vector. Try this instead,
mvn.var=matrix(c(3,1,1,4,6,7,8,9),4,2,byrow=T)
y = matrix(data=NA,2,4,byrow=T)
for (i in 1:dim(mvn.var)[2]) {
y[i,]=mvn.var[,i]
}
However you can achieve the same result by merely transposing your matrix, e.g., t(mvn.var).
You try to put a vector of length 4 into something of length 1 (=i'th element of y). The message warns you, because y[i] will only contain the first element of the column.
Try making y a list:
mvn.var=matrix(c(3,1,1,4,6,7,8,9),4,2,byrow=T)
y <- list()
for (i in 1:dim(mvn.var)[2])
y[[i]]=mvn.var[,i]
y
# [[1]]
# [1] 3 1 6 8
#
# [[2]]
# [1] 1 4 7 9

preventing R nested list from being converted to named vector

I want to create a nested list, for example,
> L <- NULL
> L$a$b <- 1
> L
$a
$a$b
[1] 1
Since I need to do assignment in loops, I have to use the brackets instead of the dollar, for example,
> L <- NULL
> a <- "a"
> b <- "b"
> L[[a]][[b]] <- 1
> L
a
1
> b <- "b1"
> L[[a]][[b]] <- 1
Error in L[[a]][[b]] <- 1 :
more elements supplied than there are to replace
That is out of my expectation: L becomes a named vector rather than a nested list. However if the assigned value is a vector whose length exceeds 1, the problem will disappear,
> L <- NULL
> L[[a]][[b]] <- 1:2
> L
$a
$a$b
[1] 1 2
> b <- "b1"
> L[[a]][[b]] <- 1
> L
$a
$a$b
[1] 1 2
$a$b1
[1] 1
Most of my assignments are longer than 1, that is the reason my code seemingly worked but at times failed strangely. I want to know if there is any way to fix this unexpected behavior, thanks.
You could explicitly say that each thing should be it's own list
> L <- list()
> L[[a]] <- list()
> L[[a]][[b]] <- 1
> L
$a
$a$b
[1] 1
But it sounds like there is probably a better way to do what you want if you explain your actual goal.
see help("[[")
When $<- is applied to a NULL x, it first coerces x to list(). This is what also happens with [[<- if the replacement value value is of length greater than one: if value has length 1 or 0, x is first coerced to a zero-length vector of the type of value.

Warning "the condition has length > 1 and only the first element will be used"

My R code:
bnc1<-function(maxITR=100000, d=2, l=1){
counts=0;
for (i in 1:maxITR){
x=runif(1,0,pi);
y=runif(2,0,d/2);
if ((l/2*sin(x)) >= y) counts=counts+1;
}
counts/maxITR*d/l
}
Running the code:
> bnc1(maxITR=1000)
[1] 0.652
There were 50 or more warnings (use warnings() to see the first 50)
> warnings()
Warning messages:
1: In if ((l/2 * sin(x)) >= y) counts = counts + 1 ... :
the condition has length > 1 and only the first element will be used
2: In if ((l/2 * sin(x)) >= y) counts = counts + 1 ... :
the condition has length > 1 and only the first element will be used
...
49: In if ((l/2 * sin(x)) >= y) counts = counts + 1 ... :
the condition has length > 1 and only the first element will be used
50: In if ((l/2 * sin(x)) >= y) counts = counts + 1 ... :
the condition has length > 1 and only the first element will be used
Does anyone has an idea what causes the warnings?
runif returns a vector.
if takes a single value (not a vector).
Check the manual for runif, I don't think you are using it right.
In R, it often makes sense to remove for loops and use vectors instead - for example:
bnc1<-function(maxITR=100000, d=2, l=1){
x=runif(maxITR,0,pi);
y=runif(maxITR,0,d/2);
counts = sum((l/2*sin(x)) >= y);
counts/maxITR*d/l
}

Resources