Как отсортировать символьный вектор, элементы которого содержат буквы и цифры?

#r

#r #сортировка #r-faq

Вопрос:

У меня есть массив символов

 cf <- c("V440","V457","V116","V327","V446","V108",
         "V155","V217","V120","V51","V477")
  

Я хотел бы отсортировать его в порядке убывания, чтобы у меня был такой результат:

 V51
V108
V116
V120
V155
V217
V327
V440
V446
V457
V477
  

Я пробовал sort.list() вот так

 cf[sort.list(cf)]
  

и получил этот ответ:

 [1] "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446" "V457" "V477" "V51" 
  

а также попробовал order() и получил тот же результат.

Кто-нибудь может мне помочь, пожалуйста

Ответ №1:

Попробуйте mixedsort из пакета «gtools»:

 > # install.packages("gtools") ## Uncomment if not already installed
> library(gtools)
> mixedsort(cf)
 [1] "V51"  "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446" "V457" "V477"
  

Если вы не хотите использовать mixedsort (не уверен, почему бы и нет), и если ваш вектор имеет довольно последовательный шаблон (например, буквы, за которыми следуют цифры), вы также, вероятно, можете попробовать что-то вроде этого. (Примечание: Относительно непроверенный.)

 newvec <- c("V440", "V457", "V116", "V327", "V446", "V108", "V155", 
            "V217", "V120", "V51", "V477", "B22", "A10", "Z01")

newvec[order(gsub("([A-Z] )([0-9] )", "\1", newvec), 
             as.numeric(gsub("([A-Z] )([0-9] )", "\2", newvec)))]
#  [1] "A10"  "B22"  "V51"  "V108" "V116" "V120" "V155" "V217" "V327" "V440"
# [11] "V446" "V457" "V477" "Z01" 
  

Ответ №2:

Здесь много правильных ответов, это другой способ, просто для развлечения.

 cf[order(nchar(cf), cf)]
# [1] "V51"  "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446" "V457" "V477"
  

Комментарии:

1. Ну, это сортирует c («привет», «привет», «привет») как «привет», «привет» и «привет», что не совсем то, что человек ожидал бы от естественного компаратора

Ответ №3:

Еще одно решение в строке кода с использованием str_sort функции (из stringr пакета).

 # install.packages("stringr") ## Uncomment if not already installed
library(stringr)
  

str_sort(cf, numeric = TRUE)

 [1] "V51"  "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446" "V457" "V477"
  

Ответ №4:

Просто удалите предыдущий символ «V», чтобы построить вектор сортировки. Никаких дополнительных навороченных инструментов не требуется.

 vals <- as.numeric(gsub("V","", cf))
cf[order(vals)]

[1] "V51"  "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446"
[10] "V457" "V477"
  

Ответ №5:

R правильно упорядочивает строки в алфавитном порядке, вот почему вы получаете этот результат.

Помимо очень хорошего ответа @Ananda, если вы хотите использовать базовый R, вы можете использовать strsplit для удаления «V» из каждой строки, а затем использовать as.numeric для преобразования строк в целые числа:

 vals <- as.numeric(sapply(cf, FUN=function(x){strsplit(x, "V")[[1]][2]}))
  

Теперь вы можете отсортировать свои строки с помощью vals

 cf[order(vals)]
  

Ответ №6:

Вот базовый подход, использующий names и sort (подход Ананды был довольно плавным):

 cf <- c("V440","V457","V116","V327","V446","V108",
         "V155","V217","V120","V51","V477")

cf2 <- as.numeric(gsub("[^[:digit:]]", "", cf))
names(cf2) <- seq_along(cf2)
cf[as.numeric(names(sort(cf2)))]

## > cf[as.numeric(names(sort(cf2)))]
##  [1] "V51"  "V108" "V116" "V120" "V155" "V217" "V327"
##  [8] "V440" "V446" "V457" "V477"