Reputation: 5897
I am working with the R programming language. Suppose I had infinite time and didn't care if this WHILE LOOP takes forever to run:
library(dplyr)
list_results <- list()
for (i in 1:100){
c1_i = c2_i = c3_i = ctotal_i = 0
while(c1_i + c2_i + c3_i < 15 && nrow_i > 5 ) {
num_1_i = sample_n(iris, 30)
num_2_i = sample_n(iris, 30)
num_3_i = sample_n(iris, 30)
c1_i = mean(num_1_i$Sepal.Length)
c2_i = mean(num_2_i$Sepal.Length)
c3_i = mean(num_3_i$Sepal.Length)
ctotal_i = c1_i + c2_i + c3_i
combined_i = rbind(num_1_i, num_2_i, num_3_i)
nrow_i = nrow(unique(combined_i[duplicated(combined_i), ]))
}
inter_results_i <- data.frame(i, c1_i, c2_i, c3_i, ctotal_i, nrow_i)
list_results[[i]] <- inter_results_i
}
In this case, I would want to this LOOP to ONLY continue to the next iteration if the current iteration produces a result where "c1_i + c2_i + c3_i > 15" AND "nrow_i <5". I thought I had correctly specified these conditions in this LOOP.
However, every time I run the above LOOP and check the results, nrow_i is never less than 5:
[[100]]
i c1_i c2_i c3_i ctotal_i nrow_i
1 100 5.796667 6.116667 5.863333 17.77667 19
In my opinion, this LOOP should have never completed running until both of these conditions have met.
My Question: How can I purposefully "sabotage" my LOOP and ensure that "nrow_i" is always less than 5, even if it takes forever to run? How should I write the code for such a scenario - can someone please suggest what to do?
Thanks!
Upvotes: 0
Views: 141
Reputation: 1812
There are two errors in your logic. Consider your requirement, and its implementation:
I want this LOOP to ONLY continue to the next iteration if the current iteration produces a result where "c1_i + c2_i + c3_i > 15" AND "nrow_i <5".
while(c1_i + c2_i + c3_i < 15 && nrow_i > 5 ) { ... }
The criteria inside while()
are of course when the loop should keep going, which should be the opposite of what you describe as criteria to stop the loop. But they aren't:
The opposite of X AND Y
should be not X OR not Y
, instead of not X AND not Y
: consider the situation where only one of them is True and the other is False.
The inverse of > 15
is <= 15
, not < 15
. And the inverse of < 5
is >= 5
. Consider the situation where the value is exactly 15 or 5, respectively.
Less prone to making mistakes between design and implementation when you're working with inverted logic is writing the opposite as not(X AND Y)
:
while(! (c1_i + c2_i + c3_i > 15 && nrow_i < 5) ) { ... }
Upvotes: 1
Reputation: 19887
Hope that I have understood the problem correctly and assuming nrow_i = 0
, I think this is what you are trying to do
library(dplyr)
list_results <- list()
nrow_i <- 0
for (i in 1:100) {
c1_i <- c2_i <- c3_i <- ctotal_i <- 0
while (TRUE) {
num_1_i <- sample_n(iris, 30)
num_2_i <- sample_n(iris, 30)
num_3_i <- sample_n(iris, 30)
c1_i <- mean(num_1_i$Sepal.Length)
c2_i <- mean(num_2_i$Sepal.Length)
c3_i <- mean(num_3_i$Sepal.Length)
ctotal_i <- c1_i + c2_i + c3_i
combined_i <- rbind(num_1_i, num_2_i, num_3_i)
nrow_i <- nrow(unique(combined_i[duplicated(combined_i), ]))
if (ctotal_i > 15 && nrow_i < 5) break
}
# if (ctotal_i <= 15 && nrow_i >= 5) break
inter_results_i <- data.frame(i, c1_i, c2_i, c3_i, ctotal_i, nrow_i)
list_results[[i]] <- inter_results_i
}
Here while loop will run till we have ctotal_i > 15
and nrow_i < 5
. (using ctotal_i since ctotal_i = c1_i + c2_i + c3_i
) and store the values in list_results
and move to next iteration.
Upvotes: 1