1

I'm very new to R, and much more new to programming in R. I have the following question and its answer (which is not mine). I've trying to understand why some values, from where they are obtained, why they are used, etc.

Question: Make the vector 3 5 7 9 11 13 15 17 with a for loop. Start with x=numeric() and fill this vector with the for loop

I know I have to create x=numeric() so I can fill it with the result obtained from the loop.

The answer from a classmate was:

> x <- numeric()
> for(i in 1:8){   
      if(i==1){                ## Why ==1 and not 0, or any other value   
          x[i] <- 3              
      }else{   
          x[i] <- x[i-1]+2  ### And why i-1   
     }

I'm having similar problems in questions like:

Make a for loop that adds the second element of a vector to the first, subtracts the third element from the result, adds the fourth again and so on for the entire length of the vector

So far, I created the vector and the empty vector

> y = c(5, 10, 15, 20, 25, 30)
> answer <- 0 

And then, when I try to do the for loop, I get stuck here:

for(i in 1:length(y)){
if(i...){ ### ==1? ==0?
    answer = y[i]   ###and here I really don't know how to continue. 
}else if()
}

Believe me when I tell you I've read several replies to questions here, like in How to make a vector using a for loop, plus pages and pages about for loop, but cannot really figure how to solve these (and other) problems.
I repeat, I'm very new, so I'm struggling trying to understand it. Any help would be much appreciated.

NelsonGon
  • 13,015
  • 7
  • 27
  • 57
Nalerive
  • 113
  • 6
  • 10
    Whoever is teaching you, tell them from the SO r-tag community to please stop teaching how to grow objects in a loop. – Roland Jan 14 '14 at 14:36
  • 3
    Also tell them to read [The R Inferno](http://www.burns-stat.com/pages/Tutor/R_inferno.pdf) to learn the reasons why @Roland suggests "stop teaching how to grow objects in a loop." – Jilber Urbina Jan 14 '14 at 14:55
  • For that matter, tell your classmate that it's insane to stick a conditional `if(i == 1) ` inside a loop. If the first value of your vector doesn't follow the pattern of the remainder, initialize outside the loop and do `for(i = 2:n)` – Carl Witthoft Jan 14 '14 at 15:23
  • @CarlWitthoft Then at what point do we teach them that using `1:length(y)` to get a set of indexes to iterate over is a bad idea (namely when `y` might have length 0)? (For future readers, `seq_along(y)` is safer because it gives the intended results even when `y` is of length 0.) – Brian Diggs Jan 15 '14 at 20:35
  • 1
    @BrianDiggs well, philosophically, I prefer to check that `length(y)` is a useful value prior to doing anything with `y` :-) – Carl Witthoft Jan 15 '14 at 21:06
  • I think teaching how to grow objects is not bad since it can help one transfer this knowledge across languages. Might be handy. – NelsonGon Jun 09 '19 at 20:43

2 Answers2

4

First, I will annotate the loop to answer what the loop is doing.

# Initialize the vector
x <- numeric()
for(i in 1:8){   
  # Initialize the first element of the vector, x[1].  Remember, R indexes start at 1, not 0.
  if(i==1){                
    x[i] <- 3              
  } else {   
    # Define each additional element in terms of the previous one (x[i - 1]
    # is the element of x before the current one.
    x[i] <- x[i-1]+2  ### And why i-1   
  }
} 

A better solution that uses a loop and grows it (like the instructions state) is something like this:

x <- numeric()
for(i in 1:8){
  x[i] <- 2 * i + 1
}

This is still not a good way to do things because growing a vector inside a loop is very slow. To fix this, you can preallocate the vector by telling numeric the length of the vector you want:

x <- numeric(8)

The best way to solve this would be:

2 * 1:8 + 1

using vectorized operations.

To help you solve your other problem, I suggest writing out each step of the loop as a table. For example, for my solution, the table would be

i | x[i]
------------------
1 | 2 * 1 + 1 = 3
2 | 2 * 2 + 1 = 5

and so on. This will give you an idea of what the for loop is doing at each iteration.

Christopher Louden
  • 7,540
  • 2
  • 26
  • 29
1

This is intentionally not an answer because there are better ways to solve the alternating sign summation problem than a for-loop. I suppose there could be value in getting comfortable with for-loops but the vectorized approaches in R should be learned as well. R has "argument recycling" for many of its operations, including the "*" (multiplication) operation: Look at:

 (1:10)*c(1,-1)

Then take an arbitrary vector, say vec and try:

sum( vec*c(1,-1) )

The more correct answer after looking at that result would be:

vvec[1] + sum( vec[-1]*c(1,-1) )

Which has the educational advantage of illustrating R's negative indexing. Look up "argument recycling" in your documentation. The shorter objects are automagically duplicatied/triplicated/however-many-needed-cated to exactly match the length of the longest vector in the mathematical or logical expression.

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • I think for loops are easier when starting because you can tell R to do something the way you think. When using vectorization in R, you first have to understand how R thinks and then change your methods to accommodate R. And I don't think it is bad not to mention pre-allocation @Roland or optimization because when people are learning (well, for me at least), I wasn't thrown into a situation working with huge databases where it was pivotal to optimize code and worry about memory management. – rawr Jan 14 '14 at 14:59
  • @rawr I don't agree fully. Pre-allocation is easy and easy to explain. One could still show that growing objects is possible, but after teaching pre-allocation and clearly explaining why it should be avoided. – Roland Jan 14 '14 at 15:04
  • It can be explained in a sentence or two and is good practice for later, so yeah you're probably right. – rawr Jan 14 '14 at 15:13
  • Thanks all for your replies! It helped a lot! – Nalerive Jan 15 '14 at 15:26