Justin Cocco
Justin Cocco

Reputation: 389

How to convert for function into lapply in R

I was hoping that you guys could help me transition from loops to more r-language. I can't figure out how to do it, despite multiple resources. Perhaps I'm just missing something, so here I am asking for your help!

Problem:

I have a list with multiple elements for which I want to iterate through, search for specific key words, and if they are present, extract specific information in relation to those hits. Where the numerics after the abbreviations are time stamps. Is there a way to 1) do this with the apply family (I'm trying to become more efficient with R language); and 2) a more efficient way overall?

Thanks in advance!

Example:

list_a <- list(
  "ENRTE 12:34 ONSCNE: 12:43 ENRTE: 13:34 ATHOSP: 14:23",
  "ENRTE 13:34 ONSNE: 13:43 ENRTE: 23:23 ATHOSP: 12:32"
)
list_a[[1]][2] <- "ENRTE 23:23 ONSCNE: 14:32 ERNTE: 17:34 ATHOSP: 13:32"
list_a[[2]][2] <- "ENRTE: 12:23 ONSCNE: 17:34 ENRTE: 17:34 ATHOSP: 14:32"

list_a

[[1]]
[1] "ENRTE 12:34 ONSCNE: 12:43 ENRTE: 13:34 ATHOSP: 14:23" "ENRTE 23:23 ONSCNE: 14:32 ERNTE: 17:34 ATHOSP: 13:32"

[[2]]
[1] "ENRTE 13:34 ONSNE: 13:43 ENRTE: 23:23 ATHOSP: 12:32"   "ENRTE: 12:23 ONSCNE: 17:34 ENRTE: 17:34 ATHOSP: 14:32"

Then my loop goes as:

k=1
enroute_list = list()
for(i in 1:length(list_a)){
   for(j in 1:length(list_a[[i]]){
       if(list_a[[i]] %>% str_extract("ENRTE") %>% is.element('ENRTE',.){
         list_a[[j]][i] %>%
         str_extract("(?<=\\/)[:digit:]{2}") -> hour_enrte
       list_a[[j]][i] %>%
         str_extract("(?<=\\:)[:digit:]{2}(?=\\:)") -> minute_enrte
       list_a[[j]][i] %>%
         str_extract("(?<=\\:)[:digit:]{2}(?!\\:)") -> second_enrte
       hour_enrte_df <- data.frame(hour_enrte)
       minute_enrte_df <- data.frame(minute_enrte)
       second_enrte_df <- data.frame(second_enrte)
       time_enroute <- cbind(hour_enrte_df, minute_enrte_df, second_enrte_df) %>%
        unite(.,enroute,1:3, sep=":")}
    while(k <= 10) {
        enroute_list[[k]] <- time_enroute
        k <- k+1
        break
     }
     enrte <- bind_rows(enrte_list)
}

This loop searches 12 terms throughout the entirety of the list (several hundred elements) and extracts the relevant info and produces a data frame at the end that looks like:

type received dispatched  enroute  onscene   enrhsp   arrhsp    avail   closed
1   AH 19:19:22   19:21:35 19:28:39 19:32:51 19:44:20 19:48:03 19:29:06 20:18:39

My loop works just fine, but it is bugging me cause everywhere I read I hear "don't use loops in R" so I figured I would try to challenge myself and transition to the apply family, but it is more daunting than I thought it would be.

Thanks again!

Upvotes: 0

Views: 46

Answers (1)

Carl Witthoft
Carl Witthoft

Reputation: 21532

There's less reason than you might think to switch to *apply , unless you like extremely compact code. In most cases there's little or no time penalty, assuming you write the loop correctly(pre-allocate space, don't calculate things you don't need, etc.).

So, along with "when in doubt, reboot," you can put "don't use loops" into the Closet Of Rarely True Things. Unless you are using loops instead of the built-in vectorized capability of most functions. Example:

for (j in 1:100) x[j] = sin(y[j]) 

vs

x = sin(y)

Upvotes: 3

Related Questions