Home > OS >  Given array of hashes, sort alphabetically then by number
Given array of hashes, sort alphabetically then by number

Time:03-23

I have an array of hashes with id and name. The names can either have digits strings or strings only. The goal is to sort alphabetically and if there are digits in the name, sort them by digit value.

Given:

array = [{id: "1", name: "Lorem 100"},
         {id: "2", name: "Lorem 101"}, 
         {id: "3", name: "Lorem 101-A"},   
         {id: "4", name: "Lorem 101-B"},  
         {id: "5", name: "Lorem 2"}, 
         {id: "6", name: "Ipsum (Lorems 55 & 55A)"},
         {id: "7", name: "Dolor"},
         {id: "8", name: "Sit"},
         {id: "9", name: "Amet"}]

Sort like this:

sorted_array = [ {id: "9", name: "Amet"},
                 {id: "7", name: "Dolor"},
                 {id: "6", name: "Ipsum (Lorems 55 & 55A)"},
                 {id: "5", name: "Lorem 2"}, 
                 {id: "1", name: "Lorem 100"},
                 {id: "2", name: "Lorem 101"}, 
                 {id: "3", name: "Lorem 101-A"},   
                 {id: "4", name: "Lorem 101-B"},  
                 {id: "8", name: "Sit"}]

What I've tried:

  1. array.sort_by { |hash| hash[:name] } -> did not sort like I wanted to i.e. Lorem 100 will be above Lorem 2
  2. array.sort_by { |hash| hash[:name][/\d /].to_i } -> gives error because not all hashes have digits

Reaching out to this great community for any resource or suggestions that may help me solve this. Thank you!

CodePudding user response:

array.sort_by { |hash|
  hash[:name].split(/(\d )/).map.with_index { |part, index|
    index.odd? ? part.to_i : part
  }
}

Split the name using consecutive digits as separator, using capture parentheses to keep separators (see String#split); then change the separators (i.e. every odd element) into integers, so they can compare numerically rather than lexicographically. Thus, sort_by will compare items such as ["Ipsum (Lorems ", 55, " & ", 55, "A)"]. Array#<=> does the intuitive thing, where ["Lorem ", 2] comes before ["Lorem ", 101].

  • Related