9

I have just started learning R and I wrote this code to learn on functions and loops.

squared<-function(x){
  m<-c()
  for(i in 1:x){
    y<-i*i
    c(m,y)
  }
  return (m)
}
squared(5)  

NULL  

Why does this return NULL. I want i*i values to append to the end of mand return a vector. Can someone please point out whats wrong with this code.

sam_rox
  • 739
  • 3
  • 14
  • 29
  • 1
    You never put anything inside `m <- c()`. – Rich Scriven Sep 03 '15 at 03:57
  • 3
    I guess you want `m <- c(m, y)` instead of just `c(m, y)`. That being said, you really shouldn't build vectors by appending one element at a time -- see the second circle of [the R inferno](http://www.burns-stat.com/pages/Tutor/R_inferno.pdf) for details. Part of the beauty of R is its vectorized operations -- you can just do `squared <- function(x) x^2`. This is both much less typing and much more efficient. – josliber Sep 03 '15 at 04:01

2 Answers2

14

You haven't put anything inside m <- c() in your loop since you did not use an assignment. You are getting the following -

m <- c()
m
# NULL

You can change the function to return the desired values by assigning m in the loop.

squared <- function(x) {
    m <- c()
    for(i in 1:x) {
        y <- i * i
        m <- c(m, y)
    }
    return(m)
}

squared(5)
# [1]  1  4  9 16 25

But this is inefficient because we know the length of the resulting vector will be 5 (or x). So we want to allocate the memory first before looping. This will be the better way to use the for() loop.

squared <- function(x) {
    m <- vector("integer", x)
    for(i in seq_len(x)) {
        m[i] <- i * i
    }
    m
}

squared(5)
# [1]  1  4  9 16 25 

Also notice that I have removed return() from the second function. It is not necessary there, so it can be removed. It's a matter of personal preference to leave it in this situation. Sometimes it will be necessary, like in if() statements for example.

I know the question is about looping, but I also must mention that this can be done more efficiently with seven characters using the primitive ^, like this

(1:5)^2
# [1]  1  4  9 16 25

^ is a primitive function, which means the code is written entirely in C and will be the most efficient of these three methods

`^`
# function (e1, e2)  .Primitive("^")
Rich Scriven
  • 97,041
  • 11
  • 181
  • 245
  • 2
    7 characters... pfft. Wasteful! – thelatemail Sep 03 '15 at 04:05
  • @thelatemail - I feel like I might have over-done it there. Haha – Rich Scriven Sep 03 '15 at 04:20
  • @RichardScriven Thank You for the explanation. I would like to know why `<-` are used and can't `=` be used in R? That is can't I code as `y=i*i`? Is it necessary to be as `y<-i*i` – sam_rox Sep 03 '15 at 05:14
  • @sam_rox either works here. You can read more about the differences here: http://stackoverflow.com/questions/1741820/assignment-operators-in-r-and – josliber Sep 03 '15 at 06:29
1

Here's a general approach:

# Create empty vector
vec <- c()

for(i in 1:10){

  # Inside the loop, make one or elements to add to vector
  new_elements <- i * 3
  
  # Use 'c' to combine the existing vector with the new_elements
  vec <- c(vec, new_elements)

}

vec
#  [1]  3  6  9 12 15 18 21 24 27 30

  • If you happen to run out of memory (e.g. if your loop has a lot of iterations or vectors are large), you can try vector preallocation which will be more efficient. That's not usually necessary unless your vectors are particularly large though.
stevec
  • 41,291
  • 27
  • 223
  • 311