Kurt W Kurt W - 1 month ago 7
Ruby Question

Ruby - sort array of hashes values (string) based on array order

I have an array of hashes in the format shown below and I am attempting to sort the

:book
key of the hash based on a separate array. The order is not alphabetical and for my use case it cannot be alphabetical.

I need to sort based on the following array:

array = ['Matthew', 'Mark', 'Acts', '1John']


Note that I've seen several solutions that leverage
Array#index
(such as Sorting an Array of hashes based on an Array of sorted values) to perform a custom sort but that will not work with strings.

I've tried various combinations of sorting with
Array#sort
and
Array#sort_by
but they don't seem to accept a custom order. What am I missing? Thank you in advance for your help!

Array of Hashes

[{:book=>"Matthew",
:chapter=>"4",
:section=>"new_testament"},
{:book=>"Matthew",
:chapter=>"22",
:section=>"new_testament"},
{:book=>"Mark",
:chapter=>"6",
:section=>"new_testament"},
{:book=>"1John",
:chapter=>"1",
:section=>"new_testament"},
{:book=>"1John",
:chapter=>"1",
:section=>"new_testament"},
{:book=>"Acts",
:chapter=>"9",
:section=>"new_testament"},
{:book=>"Acts",
:chapter=>"17",
:section=>"new_testament"}]

Answer

Here's an example

arr = [{a: 1}, {a: 3}, {a: 2}] 

order = [2,1,3]  

arr.sort { |a,b| order.index(a[:a]) <=> order.index(b[:a]) }                                           
# => [{:a=>2}, {:a=>1}, {:a=>3}]  

In your case it would be

order = ['Matthew', 'Mark', 'Acts', '1John']
result = list_of_hashes.sort do |a,b|
  order.index(a[:name]) <=> order.index(b[:name])
end

There are two important concepts here:

  1. Using Array#index to find where in an array an element is found
  2. the 'spaceship operator' <=> which is how Array#sort works - see What is the Ruby <=> (spaceship) operator?