keep duplicates using `make_clean_names` in R janitor package

Viewed 705

I am trying to clean a character column using make_clean_names function in janitor package in R. I need to keep the duplicated in this case and not add a numeric to it. Is this possible? My code is like this

x <- c(' x y z', 'xyz', 'x123x', 'xy()','xyz','xyz')

janitor::make_clean_names(x)
[1] "x_y_z" "xyz"   "x123x" "xy"    "xyz_2" "xyz_3"

janitor::make_clean_names(x, unique_sep = '.')
[1] "x_y_z" "xyz"   "x123x" "xy"    "xyz.1" "xyz.2"

janitor::make_clean_names(x, unique_sep = NULL)
[1] "x_y_z" "xyz"   "x123x" "xy"    "xyz_2" "xyz_3"

Using unique_sep = NULL doesn't seem to work. Any other way to keep unique values?

Desired Output:

[1] "x_y_z" "xyz"   "x123x" "xy"    "xyz" "xyz"

I know how to use regular expressions to do this. Just searching for a shortcut.

PS: I know this function is created to clean names of a data.frame, I am trying to apply this to a different use case. This functionality might help a lot in cleaning character columns.

2 Answers

Unfortunately no, it's not possible. If you look at the code for make_clean_names you'll see it ends with this:

 # Handle duplicated names - they mess up dplyr pipelines.  This appends the
  # column number to repeated instances of duplicate variable names.
  while (any(duplicated(cased_names))) {
    dupe_count <-
      vapply(
        seq_along(cased_names), function(i) {
          sum(cased_names[i] == cased_names[1:i])
        },
        1L
      )
  
    cased_names[dupe_count > 1] <-
      paste(
        cased_names[dupe_count > 1],
        dupe_count[dupe_count > 1],
        sep = "_"
      )
  }

I think you're on the right track passing the unique_sep argument through to the underlying function that make_clean_names uses, snakecase::to_any_case. But that while loop, recently introduced to ensure there are never duplicated names resulting from make_clean_names, will always deduplicate at the end.

You could try adapting your own function that is the first part of make_clean_names, without the loop, or you could perhaps make use of snakecase::to_any_case.

You can use sapply to go through the vector elements one by one and thus avoid adding numeric suffixes to duplicates:

sapply(x, make_clean_names, USE.NAMES = F)
[1] "x_y_z" "xyz"   "x123x" "xy"    "xyz"   "xyz"
Related