I am trying to create a loop in R that allows me to change the value of an object within the loop.
Below is an easy example to point out what exactly I mean by this. Print(x) stands for a rather extensive bulk of code, in which the value of x is needed for certain computations. However, while solution #1 works on paper, it is not usable in this context (because of sub loops). Is there any way to design a loop in R that resembles solution #2? Thanks a lot in advance!
1> x <- 1
2> while (x == 1)
3> {
4> print(x)
5> x <- 2
6> print(x)
7> x <- 3
8> print(x)
9> x <- 4
10> print(x)
11> if (x == 4)
12> break
13> }
Output
1
2
3
4
1> x <- 1
2> while (x == 1 || x == 2 || x == 3 || x == 4)
3> {
4> print (x)
5> x <- 2
#jump to line 2, ignore line 5, proceed with line 6
6> x <- 3
#jump to line 2, ignore line 6, proceed with line 7
7> x <- 4
#jump to line 2, ignore line 7, proceed with line 8
8> if (x == 4)
9> break
10> }
Output
1
2
3
4
It is somewhat hard to tell what exactly you want to do, but I'll give a shot, too. So you first might want to write a function that takes the value of x and does computations depending on the value of x (as far as I got it from your example, the computations/loops are not the same for all x).
x <- 1:4
fct <- function(x) {
if (x==1){
y <- x^2
}
if (x==2) {
y <- x + 2
}
if (x>2 & x < 5) {
y <- x*3 + 4
}
return(y)
}
Now loop over x:
sapply(x, fct)
Is that what you want?
I'm not sure it's gonna work because it's not clear exactly what you want to do, but could you try to put in a vector all the values you want to run print on? Like this:
my_values <- c(1,2,3,4)
for(x in my_values) {
print(x)
}
EDIT:
What I am gonna may be totally useless, but are you getting your next key from RODBC as well? If that's the case, suppose that you can get your next key with a function get_next_key and your data with get_data. I also assume that get_next_key returns NA if there is no more key (i.e you had the last key before). Would that work:
x = 1
while(!is.na(get_next_key(x))) {
data = get_data(x)
print(data)
x = get_next_key(x)
}
This first obviously works only for integer increments of x:
x <- 1
while (x <= 4){
print(x)
x <- x+1
}
For arbitrary values of x:
x1 <- c(1, 2, 3, 4)
### index x1 and move along this;
### at each step assign the value to y1 then
### do something with (print) it
for (i in seq_along(x1)) print(y1 <- x1[i])
Nothing really wrong with a for loop here and sometimes easier to read than apply
Related
I am in an intro to R course and the professor has not been much help. One of the questions on the latest homework has me stumped. The question is below, along with my answers so far.
8. [15 points] Given the following code,
#
# x <- rnorm(10)
#
# Do the following.
#
# (1) create a count vector named "count" of four elements and set each to 0 using the rep function.
# (2) using a for loop to process each value in the vector x, count how many times each of the following values occur in the vector x using an if statement.
# a. "value is between -1 and 1 inclusive"
# b. "value is between -2 and 2 inclusive, but not between -1 and 1",
# c. "value is between -3 and 3 inclusive, but not between -2 and -2", or
# d. "value is greater than 3 or less than -3".
# (3) print each of the four counts in the count vector using a while loop.
#
# For example, if the vector x contains the following ten values,
#
# 1.1478911 1.6183994 -2.3790632 -0.2566993 0.8923735
# -0.7523441 -0.7559083 0.9836396 1.0994189 2.5519972
#
# Then, the output should be as below.
#
# count[1] is 5
# count[2] is 3
# count[3] is 2
# count[4] is 0
x <- rnorm(10)
My answers:
(1) count <- c(rep(0,4))
(2)
for (count in x) {
if (x > -1 & x < 1) {
print(count[1])
}
I know there is something wrong with my code for part one but we haven't gone over anything like this in class and I have struggled to find a video for something like this. Please point me in the right direction and let me know what mistakes I have made, thanks so much!
You part one is correct. Maybe you can remove the initial c() from it.
x <- rnorm(10)
#Part 1
count <- rep(0,4)
#Part 2
for(i in x) {
if(i >= -1 && i <= 1)
count[1] <- count[1] + 1
else if(i >= -2 && i <= 2)
count[2] <- count[2] + 1
else if(i >= -3 & i <= 3)
count[3] <- count[3] + 1
else count[4] <- count[4] + 1
}
#Part 3
i <- 0
while (i < length(count)) {
i <- i + 1
print(sprintf('count[%d] is: %d', i, count[i]))
}
Note that there are better/efficient ways to do this but I think for the purpose of this exercise this is what your professor wants.
Each of the 4 slots in count is supposed to keep track of whether a value in x satisfies one of the 4 conditions listed (a. through d.).
If we were to speak it out loud, it'd go something like:
Look at element 1 in x (you can do that with x[1]). It's 1.1478911. This satisfies condition b., so add a 1 to the "b. counter", which is the second slot in count, or count[2].
Now look at element 2 in x (that's x[2])...(and so on, up to the last element in x).
To solve this task, you could just write out 10 statements, looking at each of the 10 elements in x separately, and update count on a case-by-case basis, but that is long and is hard to modify.
A for-loop is kind of like making a template for the spoken-out-loud part above. So instead of saying, "Ok, now we're on Element 3, let's see what the deal is", you can instead say, "Ok, now we're on Element i...", where i is just a temporary variable, a placeholder that only exists for the life of the for-loop. The i placeholder automatically takes on the value of the element in the vector we're iterating over.
If it's for (i in 1:3) then i will be 1, then 2, then 3.
If it's for (letter in c("a", "b", "c")), then letter will be "a", then "b", then "c".
So you can see that when you write for (count in x), that doesn't follow the rules of the for-loop. It's true that we'll want to update count at some point in the loop, but you've got it in the spot where our temporary placeholder is supposed to go. You can call that placeholder whatever you want, but i is common when looping over numbers, by convention.
Here's an example: the following code will start i at 1, and repeat the code inside the loop statement with new integers, until i gets to 10:
for (i in 1:10) {
print(paste("i is", i, "and the i'th value of x is", x[i]))
}
That should be enough to get you over the part you're stuck on.
A couple of additional hints:
f you want to know how many things are in a vector, such as x, you can use length(x) (try it, you will see the output is 10). So instead of doing: for(i in 1:10), you can swap out 10 for length(x).
count[3] <- count[3] + 1 adds 1 to whatever the current total is in the third element of count.
Good luck! Someone may post the answer to the whole problem, but if you want to work through each piece, I hope this is a good jump start for you.
I have a problem with a function of the following kind:
fun.name <- function(x,y) {
a<-x
b<-y
for (i in c(a, b)){
i<-i+1
print (i)
}
print(a)
print(b)
}
fun.name(1, 2)
The result is
[1] 2
[1] 3
[1] 1
[1] 2
The same result is obtained if I do not create any a and b and I simply keep x and y ( fun.name <- function(x,y) { for (i in c(a, b))...).
I cannot understand this behavior.
What I wanted was a function which adds one to every arguments and prints the results. Why does not the loop modify the variables a and b when it is defined within the function? I guess it is a problem of environments, and that I have not understood the nature of a function arguments.
Thank you for any suggestions.
I actually expect to see your current output. Here is your code, formatted, with explanations as comments:
fun.name <- function(x,y) {
a <- x
b <- y
for (i in c(a, b)) { # i in (1, 2)
# first iteration: i = 2, print 2
# second iteration: i = 3, print 3
i <- i+1
print(i)
}
print(a) # prints 1 (a was only assigned once)
print(b) # prints 2 (same reason as above)
}
fun.name(1, 2)
There are no changes to a and b after their initial assignments inside the function. But, even if there were changes, the variables a and b would not even be visible outside the scope of the function.
Suppose I have the following code:
x <- 1
repeat
{
x <- x+1
print(x)
if (x>10)
{
break
}
}
When I run this, the value of x increases by one, and this x value is printed on to the console until the value of x becomes greater than ten. I have all the values I want of x printed on the console. However, I want to store these values as a vector. How would I do this?
x<-1
vec<-c()
while(x<11){
x<-x+1
vec<-c(vec,x)
}
vec
[1] 2 3 4 5 6 7 8 9 10 11
You can slightly modify your code:
x <- 1
y <- NULL
repeat
{
x <- x+1
print(x)
y <- c(y, x)
if (x>10)
{
break
}
}
I don't know why you choose this process to generate such a vector but I follow #Moody_Mudskipper's logic.
You should use something simple like x <- 2:11 or x <- seq(2, 11, by = 1).
Have a look at the seq() function too
I am relatively new to R and am a little bit confused about for loops.
I tried to repeat several steps within a for loop after a specified condition is hit. I tried to put the loop one step back, but have recognized that the loop keeps counting up and ignores my command. Here is a simple example to illustrate what I meant:
a <- 1:10
b <- rep(NA, 15)
fun <- function(){
i <- 1
for(i in 1:10){
b[i] <- a[i]
i <- i - 1 # This is the line I am talking about.
}
return(b)
}
fun()
[1] 1 2 3 4 5 6 7 8 9 10 NA NA NA NA NA
I have expected that this code would run forever and assigns only 1's. Is there a way how I could move one step back within for loops or would I have to do a completely different approach?
Thanks a lot in advance!
The way a for loop works is that if you have for (i in 1:10), first i is set to 1, and the body of the loop is executed. Then we go back to the top and i is set to 2, and the body of the loop is executed again. Basically, this loop:
for (x in 1:3) {
print(x^2)
}
is equivalent to this code:
x = 1
print(x^2)
x = 2
print(x^2)
x = 3
print(x^2)
So your attempt to roll the loop back a step by changing i doesn't work because the for loop doesn't actually monitor what i is, it just runs the body of the loop once for each element of the original 1:10 sequence.
If you want to sometimes repeat a step, you should use a while loop and increment i manually:
a <- 1:10
b <- rep(NA, 15)
i <- 1
while (i <= 10) {
b[i] <- a[i]
# Flip a coin, don't move on if it comes up tails
# Replace this test with the relevant condition you
# want to check for
if (sample(c(0, 1), 1) == 1) {
i <- i + 1
} else {
print(paste("Repeating with i =", i))
}
}
I want to iterate a loop only for some values so I am using this:
present <- c(3,5,7,8)
for(i in present)
{
print(i)
}
which gives me
[1] 3
[1] 5
[1] 7
[1] 8
however I need to jump to the next value within the loop, say I dont want 5 to be printed in above example.
I cannot use next since I want it in nested for like this
present <- c(3,5,7,8)
for(i in present)
{
k <- i
"Jump to next value of present"
while(k < "The next value for i should come here")
{
k <- k + 1
print(k)
}
}
The output would be 3 4 5 6 7 8 but the condition must check value of k if it exceeds next value of i.
Is there anyway to accomplish this?
I'll take help of C to explain further,
for(i=0; i < 10; i++)
{
for(k=i;k <= i+1;k++)
{
printf("%d", k);
}
}
The link contains output of above code
http://codepad.org/relkenY3
It is easy in C since next value is in sequence, but here next value is not known, hence the problem.
What you should do is loop through two vectors:
x <- head(present, -1)
# [1] 3 5 7
y <- tail(present, -1)
# [1] 5 7 8
and the function to do that is mapply (have a look at ?mapply). A close translation of your pseudo-code would be:
invisible(mapply(function(x, y) while(x < y) {x <- x + 1; print(x)}, x, y))
but maybe you'll find this more interesting:
mapply(seq, x + 1, y)
I suspect the answer is to use seq_along and use it as an index into "present", but as others have pointed out your code does not promise to deliver what you expect, even with that simple modification. The K <- K=1 assignment jumps ahead too far to deliver a value of 3 at any point and the termination condition is likewise not clear. It turns into an infinite loop in the form you construct. Work with this;
present <- c(3,5,7,8)
for(i in seq_along(present))
{
k <- i
while(k < length(present) )
{
k <- k + 1
print(present[k])
}
}