BillyBouw
BillyBouw

Reputation: 338

Save conditions for logical tests as object R

I have a list of data frames, which I want to perform a function on. I want to loop through the list of data frames and transform them based on a certain condition which is unique to the data frame. So essentially, I have two lists:

  1. A list of data frames on which I want to perform the function
  2. A list of conditions, paired with each data frame

To give an example, the first data frame I use is called HMM, and the condition is that it has to start with a certain string, and ends with 8 numbers;

if (nrow(HMM) > 0){                                                            ​
 ​for (i in 1:nrow(HMM)){
   ​if (startsWith(HMM$DELREF[i],"RTMA") &
       ​!is.na(as.numeric(substr(HMM$DELREF[i],5,nchar(HMM$DELREF[i])))) & 
       ​nchar(substr(HMM$DELREF[i], 5, nchar(HMM$DELREF[i]))) == 8
       ​){
     ​HMM[i,] <- NA
   ​}
 ​}
 ​HMM <- HMM[complete.cases(HMM),]
 ​HMM <- HMM %>% select(2,3,1,4)
}

But I want to build something like this;

for (df in dflist){
  for (condition in conditionlist){
    if (nrow(df) > 0){                                                          
      for (i in 1:nrow(df)){
        if (condition){
          df[i,] <- NA
        }
      }
      df <- df[complete.cases(df),]
      df <- df %>% select(2,3,1,4)
    }
  }
}

So now my question is; is it possible to save the condition(s) (like in the example) as an object/list/something to use in the loop?

Kind regards

Upvotes: 0

Views: 325

Answers (2)

Zoe
Zoe

Reputation: 1000

I think you look for eval() and expression()?

condition <- expression(a == 3)
a <- 2
if (eval(condition)) {
  print("yes")
} else {
  print("no")
}

[1] "no"

condition <- expression(a == 3)
a <- 3
if (eval(condition)) {
  print("yes")
} else {
  print("no")
}

[1] "yes"

If you have your conditions as strings, you can use condition <- parse(text = "a == 3").

Upvotes: 1

user2554330
user2554330

Reputation: 44867

The easiest way to save code for re-use is to put it in a function. You can put a lot of small functions in a list, or have one big function that decides which test to use. For example,

conditions <- list(
     function(df, i) 
       startsWith(df$DELREF[i],"RTMA") &&
       ​!is.na(as.numeric(substr(df$DELREF[i],5,nchar(df$DELREF[i])))) && 
       ​nchar(substr(df$DELREF[i], 5, nchar(df$DELREF[i]))) == 8,

     function(df, i) { # some other condition }
)

Then your loop could be

 condition <- conditions[[1]]
 for (i in seq_len(nrow(HMM))) {
   if (condition(HMM, i))   
     ​HMM[i,] <- NA
​ }
 HMM <- HMM[complete.cases(HMM),]
​ HMM <- HMM %>% select(2,3,1,4)

Upvotes: 1

Related Questions