how do I change a block of repeated code into a loop that adds data to a dataframe with a filter?

Viewed 21

I have these lines of code in r:

df_main$elapsed[df_main$milestone_id==1] <- df_main_cal$elapsed_ms1
df_main$elapsed[df_main$milestone_id==2] <- df_main_cal$elapsed_ms2
df_main$elapsed[df_main$milestone_id==3] <- df_main_cal$elapsed_ms3
df_main$elapsed[df_main$milestone_id==4] <- df_main_cal$elapsed_ms4
df_main$elapsed[df_main$milestone_id==5] <- df_main_cal$elapsed_ms5
df_main$elapsed[df_main$milestone_id==6] <- df_main_cal$elapsed_ms6
df_main$elapsed[df_main$milestone_id==7] <- df_main_cal$elapsed_ms7
df_main$elapsed[df_main$milestone_id==8] <- df_main_cal$elapsed_ms8
df_main$elapsed[df_main$milestone_id==9] <- df_main_cal$elapsed_ms9
df_main$elapsed[df_main$milestone_id==10] <- df_main_cal$elapsed_ms10
df_main$elapsed[df_main$milestone_id==11] <- df_main_cal$elapsed_ms11
df_main$elapsed[df_main$milestone_id==12] <- df_main_cal$elapsed_ms12

And I want to change them to a loop, something like this:

for(i in 1:12){
     df_main[[paste("elapsed[df_main$milestone_id==", 1, "]", sep = "")]] <- df_main_cal[[paste("elapsed_ms", 1, sep="")]]
 }

But when I run this code block I get this error:

Assigned data `df_main_cal[[paste("elapsed_ms", 1, sep = "")]]` must be compatible with existing data.
✖ Existing data has 4657 rows.
✖ Assigned data has 407 rows.
ℹ Only vectors of size 1 are recycled.

Any help on a more efficient way to code these lines is appreciated. Thanks in advance.

1 Answers

A loop is probably not the most efficient way to accomplish this. It seems that you already have the milestone metadata encoded in the column names of df_main_cal. Therefore, perhaps you can just use tidyr::pivot_longer() on df_main_cal to get what you need.

I simulated a snipped of data structured like what you describe for this example.

If there are additional data or metadata columns in df_main that you need you can always do a join/merge afterwards on the milestone column.

library(tidyverse)

a <- as_tibble(matrix(1:16, 
                      dimnames = list(NULL, paste0("elapsed_ms", 1:4)), 
                      nrow = 4))

a %>%
  pivot_longer(
    everything(),
    names_prefix = "elapsed_ms",
    names_to = "milestone",
    values_to = "elapsed"
  )
#> # A tibble: 16 × 2
#>    milestone elapsed
#>    <chr>       <int>
#>  1 1               1
#>  2 2               5
#>  3 3               9
#>  4 4              13
#>  5 1               2
#>  6 2               6
#>  7 3              10
#>  8 4              14
#>  9 1               3
#> 10 2               7
#> 11 3              11
#> 12 4              15
#> 13 1               4
#> 14 2               8
#> 15 3              12
#> 16 4              16

Created on 2022-09-22 by the reprex package (v2.0.1)

Related