Я пытаюсь отсортировать вектор символов в естественном порядке (как это сделал бы человек), но с учетом различий в регистрах. Например, в приведенном ниже векторе я хотел бы отсортировать все маленькие «m» и большие «M» независимо.

x<- c("m10", "M10", "m11", "m12", "m2", "M2", "m3", "M3", "m4", "M4", "yo1", "yo2")

Чтобы это выглядело так:

  DesiredSort(x)

 [1] "M2" "M3" "M4" "M10" "m2" "m3" "m4" "m10" "m11" "m12" "yo1" "yo2"

Из здесь я узнал, как сделать sort принять во внимание случай:

sortC <- function(...) {
  a <- Sys.getlocale("LC_COLLATE")
  on.exit(Sys.setlocale("LC_COLLATE", a))
  Sys.setlocale("LC_COLLATE", "C")
  sort(...)
} 
sortC(x)

[1] "M10" "M2"  "M3"  "M4"  "m10" "m11" "m12" "m2"  "m3"  "m4" "yo1" "yo2"

Но это не дает естественного порядка. Я знаю, что mixedsort из gtools правильно поместит m2 перед m10, так что:

mixedsort(x)

[1] "m2"  "M2"  "m3"  "M3"  "m4"  "M4"  "m10" "M10" "m11" "m12" "yo1" "yo2"

Но mixedsort специально игнорирует регистр символьной строки, поэтому выполнение функции, аналогичной SortC, не работает.

У меня есть несколько векторов для сортировки таким образом, и они включают символы, не включенные в пример, поэтому было бы здорово найти общий способ сделать это.

Идеи? Может быть, я упускаю что-то очевидное. Спасибо.

3
A.Mstt 2 Сен 2013 в 15:47
Должны ли в ожидаемом результате "m11" и "m10" быть наоборот?
 – 
Richie Cotton
2 Сен 2013 в 15:58

1 ответ

Лучший ответ

Насколько общим должно быть решение? Это настраиваемое решение, приведенное ниже, подходит для вашего набора данных, но не совсем понятно (по крайней мере, для меня), что вы хотите сделать в общем случае вектора, содержащего произвольные строки.

DesiredSort <- function(x)
{
  library(stringr)

  locale <- Sys.getlocale("LC_COLLATE")
  on.exit(Sys.setlocale("LC_COLLATE", locale))
  Sys.setlocale("LC_COLLATE", "C")

  x_matches <- str_match(x, "(^[[:alpha:]]+)([[:digit:]]+)")[, 2:3]

  x_data <- data.frame(
    letter = x_matches[, 1], 
    number = as.numeric(x_matches[, 2])
  )
  o <- with(x_data, order(letter, number))
  x[o]
}

x <- c("m10", "M10", "m11", "m12", "m2", "M2", "m3", "M3", "m4", "M4", "yo1", "yo2")
expected <- c("M2", "M3", "M4", "M10", "m2", "m3", "m4", "m10", "m11", "m12", "yo1", "yo2")
stopifnot(identical(DesiredSort(x), expected))
3
Richie Cotton 2 Сен 2013 в 18:11
Спасибо @Richie, я должен был сказать, что у меня есть несколько векторов, которые можно заказать аналогичным образом, но у них разные символы. Например, вы можете добавить к этому вектору «yo1», «yo2». Думаю, мне нужно что-то более общее? Я отредактирую вопрос, чтобы отразить это.
 – 
A.Mstt
2 Сен 2013 в 16:24
@ A.Mstt: обновлено более общим решением. Подумайте о том, чтобы написать несколько тестовых примеров, чтобы полностью понять форму ваших входных данных и то, каким, по вашему мнению, должен быть результат. Взгляните на пакеты testthat или RUnit для этого.
 – 
Richie Cotton
2 Сен 2013 в 18:13