Brian Smith
Brian Smith

Reputation: 1353

Sorting a vector based on the values

Let say I have below vector

vec = c('1d', '3m', '5d', '10y', '1m')

here, m means months, d means day, and y means year. I want to sort the vector in ascending order of day, month, and year. So ideally the sorted vector will be -

c('1d', '5d', '1m', '3m', '10y')

Is there any way to achieve this using R's base libraries (I am restricted to download contributed packages).

Thanks for your time.

Upvotes: 0

Views: 56

Answers (3)

akrun
akrun

Reputation: 886938

We can use str_replace

library(stringr)
vec[order(sapply(str_replace_all(vec, setNames( c('*1', '*30', '*365'), 
    c('d', 'm', 'y'))), function(x) eval(parse(text = x))))]
#[1] "1d"  "5d"  "1m"  "3m"  "10y"

Or an option with separate

library(dplyr)
library(tidyr)
tibble(vec) %>% 
   separate(vec, into = c('v1', 'v2'), sep='(?<=\\d)(?=\\D)',
         convert = TRUE, remove = FALSE) %>% 
   arrange(v2, v1) %>%
   pull(vec)
#[1] "1d"  "5d"  "1m"  "3m"  "10y"

Or can also use a matching with a named vector to order

vec[order(readr::parse_number(vec) * 
  (setNames(c(1, 7, 30, 365), c('d', 'w', 'm', 'y'))[str_remove(vec, '\\d+')]))]
#[1] "1d"  "5d"  "1m"  "3m"  "10y"

data

vec <- c('1d', '3m', '5d', '10y', '1m')

Upvotes: 0

ThomasIsCoding
ThomasIsCoding

Reputation: 101064

Since the lexical order of d, m and y is d < m < y already, you can try the code below

> vec[order(gsub("\\d+", "", vec), as.numeric(gsub("\\D+", "", vec)))]
[1] "1d"  "5d"  "1m"  "3m"  "10y"

Upvotes: 0

Ronak Shah
Ronak Shah

Reputation: 388817

Extract d, m and y value separately and extract the number separately. Create a vector of correct_order that you want, use match to get corresponding number and use it in order.

vec = c('1d', '3m', '5d', '10y', '1m')
correct_order <- c('d', 'm', 'y')

vec[order(match(gsub('\\d', '', vec), correct_order), 
          as.numeric(gsub('\\D', '', vec)))]

#[1] "1d"  "5d"  "1m"  "3m"  "10y"

Upvotes: 2

Related Questions