I would go with making a separate list of possible sites:
Possible_Sites <- c("Charlie","Delta","Echo")
If the geographic diversity criterion is broken, then you can take these Possible_Sites, and remove the Target_Sites that are already used with setdiff(). Since you may have several, you can just use sample() to randomly take one. So this becomes:
df %>%
mutate(Target_Site = case_when(
Current_Site == "Alpha" ~ "Charlie",
Current_Site == "Bravo" ~ "Delta",
Current_Site == "Charlie" ~ "NONE",
Current_Site == "Delta" ~ "NONE"
)
) %>%
group_by(App_ID, Env) %>%
mutate(Backup_Target_Site = ifelse(any(Current_Site %in% Target_Site),
sample(setdiff(Possible_Sites, Target_Site),1),
"NONE")) %>%
ungroup()
#> # A tibble: 14 x 5
#> App_ID Current_Site Env Target_Site Backup_Target_Site
#> <chr> <chr> <chr> <chr> <chr>
#> 1 1 Alpha Dev Charlie NONE
#> 2 1 Alpha Test Charlie NONE
#> 3 1 Bravo Prod Delta NONE
#> 4 1 Charlie Prod NONE NONE
#> 5 2 Alpha Dev Charlie NONE
#> 6 2 Alpha Test Charlie NONE
#> 7 2 Delta Prod NONE NONE
#> 8 3 Bravo Dev Delta NONE
#> 9 3 Charlie Test NONE NONE
#> 10 3 Bravo Prod Delta Charlie
#> 11 3 Delta Prod NONE Charlie
#> 12 4 Bravo Dev Delta NONE
#> 13 4 Charlie Test NONE NONE
#> 14 4 Alpha Prod Charlie NONE
Created on 2020-12-07 by the reprex package (v0.3.0)
Where the rows 10 and 11 may have Charlie or Echo randomly at each run.
At this point there is still one thing unsatisfying, which is the case where no value is available, in that case the entire pipeline fails with an error. If this is a case that can occur, you will need to be able to recover from the error, for example putting the code in a separate function:
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
App_ID <- c("1","1","1","1","2","2","2","3","3","3","3","3","4","4","4")
Current_Site <- c("Alpha","Alpha","Bravo","Charlie","Alpha","Alpha","Delta","Bravo","Charlie","Bravo","Delta","Alpha","Bravo","Charlie","Alpha")
Env <- c("Dev", "Test", "Prod", "Prod", "Dev", "Test", "Prod", "Dev", "Test", "Prod", "Prod","Prod", "Dev", "Test", "Prod")
df <- data.frame(App_ID, Current_Site, Env)
get_site <- function(Target_Site){
tryCatch(sample(setdiff(Possible_Sites, Target_Site),1),
error = function(e) "PROBLEM")
}
Possible_Sites <- c("Charlie","Delta")
df %>%
mutate(Target_Site = case_when(
Current_Site == "Alpha" ~ "Charlie",
Current_Site == "Bravo" ~ "Delta",
Current_Site == "Charlie" ~ "NONE",
Current_Site == "Delta" ~ "NONE"
)
) %>%
group_by(App_ID, Env) %>%
mutate(Backup_Target_Site = ifelse(any(Current_Site %in% Target_Site),
get_site(Target_Site), "NONE")) %>%
ungroup()
#> # A tibble: 15 x 5
#> App_ID Current_Site Env Target_Site Backup_Target_Site
#> <chr> <chr> <chr> <chr> <chr>
#> 1 1 Alpha Dev Charlie NONE
#> 2 1 Alpha Test Charlie NONE
#> 3 1 Bravo Prod Delta NONE
#> 4 1 Charlie Prod NONE NONE
#> 5 2 Alpha Dev Charlie NONE
#> 6 2 Alpha Test Charlie NONE
#> 7 2 Delta Prod NONE NONE
#> 8 3 Bravo Dev Delta NONE
#> 9 3 Charlie Test NONE NONE
#> 10 3 Bravo Prod Delta PROBLEM
#> 11 3 Delta Prod NONE PROBLEM
#> 12 3 Alpha Prod Charlie PROBLEM
#> 13 4 Bravo Dev Delta NONE
#> 14 4 Charlie Test NONE NONE
#> 15 4 Alpha Prod Charlie NONE
Created on 2020-12-07 by the reprex package (v0.3.0)
(in this example I added a row with Alpha->Charlie to make it unavailable, and removed Echo from the list of possibilities)