'Given array of hashes, sort alphabetically then by number
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:
- array.sort_by { |hash| hash[:name] } -> did not sort like I wanted to i.e. Lorem 100 will be above Lorem 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!
Solution 1:[1]
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].
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
