I'm not sure how elegant this is either, but it seems to get the job done. The first duplicated() call identifies the second (or further) instance of the duplicated row and then I combine it with the fromLast = TRUE option to identify the first instance of the duplicate.
library(dplyr)
df <- tibble(
x1 = c("joe", "ann", "ann", "sam", "sam", "ken"),
x2 = c("boston", "new york", "hartford", "montreal", "boise", "tulsa")
)
df %>%
mutate(x1 = if_else(
duplicated(x1) | duplicated(x1, fromLast = TRUE),
paste0(x1, " - ", x2),
x1
))
#> # A tibble: 6 x 2
#> x1 x2
#> <chr> <chr>
#> 1 joe boston
#> 2 ann - new york new york
#> 3 ann - hartford hartford
#> 4 sam - montreal montreal
#> 5 sam - boise boise
#> 6 ken tulsa
Adding: and here's another way of doing it. Elegance not guaranteed!
df %>%
mutate(x1 = if_else(
x1 %in% x1[duplicated(x1)],
paste0(x1, " - ", x2),
x1
))
#> # A tibble: 6 x 2
#> x1 x2
#> <chr> <chr>
#> 1 joe boston
#> 2 ann - new york new york
#> 3 ann - hartford hartford
#> 4 sam - montreal montreal
#> 5 sam - boise boise
#> 6 ken tulsa