Mutate multiple columns to different values, given a condition on one of the columns

I have a problem which is very similar to this Stack Overflow question, but in my case different columns need to be set to different values:

Sample data frame:

dframe <- structure(list(y = c(-0.551803287760631, -1.30494019324738, 0.00821236626893252, 
0.638916511414093, -0.816805971651003, 1.12037288852287), Date_1 = structure(c(1420217760, 
1420217760, 1420217880, 1420217880, 1420217880, 1420217880), class = c("POSIXct", 
"POSIXt"), tzone = "UTC"), Date_2 = structure(c(NA, NA, 1468065900, 
1468065900, 1468065900, 1468065900), class = c("POSIXct", "POSIXt"
), tzone = "UTC"), days_A = c(1042L, 1042L, 554L, 554L, 554L, 
554L), Date_3 = structure(c(1420217880, 1420217880, 1420218180, 
1420218180, 1420218180, 1420218180), class = c("POSIXct", "POSIXt"
), tzone = "UTC"), Date_4 = structure(c(NA, NA, 1468065900, 1468065900, 
1468065900, 1468065900), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    days_B = c(0, 0, 554, 554, 554, 554)), class = "data.frame", .Names = c("y", 
"Date_1", "Date_2", "days_A", "Date_3", "Date_4", "days_B"), row.names = c(NA, 
-6L))

I want to set days_B = days_A, Date_3 = Date_1 and Date_4 = Date_2, when days_B = 0. In other words, I want to mutate multiple columns, each one to a different value, whenever a condition on a certain column is met. If the condition is not met, the columns are not mutated, or equivalently they're set to their actual values. In other words, if, when days_B != 0, we need anyway to take some action, we can set days_B = days_B, Date_3 = Date_3 and Date_4 = Date_4. How can I do that in dplyr?

Just use if_else:

mutate(days_B = if_else(days_B == 0, days_A, days_B), 
       Date_3 = if_else(days_B == 0, Date_1, Date_3), 
       Date_4 = if_else(days_B == 0, Date_2, Date_4))
2 Likes

Careful -- referencing days_B after the line that changes it will typically result in the subsequent if_else lines referencing the updated days_B, meaning that none of them will be == 0. You would want to move days_B line to the end.

Also, the given example has different types for days_A (integer) and days_B (double). For if_else, one of them will have to be converted (as.double or as.integer).

mutate(dframe,
       Date_3 = if_else(days_B == 0, Date_1, Date_3), 
       Date_4 = if_else(days_B == 0, Date_2, Date_4),
       days_B = if_else(days_B == 0, days_A, as.integer(days_B)))
3 Likes

Well spotted on the order of the conditions and the types.