Home > Software design >  In Ruby, how can I sort an array of hashes
In Ruby, how can I sort an array of hashes

Time:02-01

I am new to Ruby, could someone help?

I have some product data Json that I need to sort by the expiry date, however everything thing I have tried with .sort_by so far is erroring.

The Json is in this format

{"wh_Repeating":[
    {
      "wh": {
        "Item_Number": "111166",
        "Expiry_Date": "2023-05-05"
      }
    },
    {
      "wh": {
        "Item_Number": "111167",
        "Expiry_Date": "2023-05-01"
      }
    },
    {
      "wh": {
        "Item_Number": "111168",
        "Expiry_Date": "2023-05-09"
      }
      }]}

in Ruby that shows as

{:wh_Repeating=>[
{:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}}, 
{:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}}, 
{:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}
]}

tried alsorts latest attempt was

sorted = jsonIn["wh_Repeating"]
sorted.sort_by { |k,v| v[:"Expiry_Date"] }
puts sorted

which gave me undefined method `sort_by' for nil:NilClass (NoMethodError) (Exception)

CodePudding user response:

Your hash keys are symbols not strings.

jsonIn["wh_Repeating"] should be jsonIn[:wh_Repeating]

Also, sorted.sort_by { |k,v| v[:"Expiry_Date"] } does not mutate sorted.

sort_by does not mutate the receiver. In other words, the value of sorted remains the same. There is a bang version (sort_by!) that does mutate (a side-effect) but the use of mutating functions is discouraged.

This does what you want to do.

jsonIn[:wh_Repeating].sort_by { |h| h.dig(:wh, :Expiry_Date) }

CodePudding user response:

I would do it like this:

data = {:wh_Repeating=>
         [{:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
          {:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
          {:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}]}

data[:wh_Repeating].sort_by! { |hash| hash[:wh][:Expiry_Date] }

data
#=>   {:wh_Repeating=>               
        [{:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
         {:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
         {:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}]}

CodePudding user response:

I have assumed the original hash (h below) is not to be mutated (modified).

h = { :wh_Repeating=>[
        {:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
        {:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
        {:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}
      ]
    }

As this hash has a single key (:wh_Repeating), we can simply write the structure of the desired hash as

{ :wh_Repeating=>... }

and then compute the value of :wh_Repeating.

{ :wh_Repeating=>h[:wh_Repeating].sort_by { |g| g[:wh][:Expiry_Date] } }
  #=> { :wh_Repeating=>[
  #       {:wh=>{:Item_Number=>"111167", :Expiry_Date=>"2023-05-01"}},
  #       {:wh=>{:Item_Number=>"111166", :Expiry_Date=>"2023-05-05"}},
  #       {:wh=>{:Item_Number=>"111168", :Expiry_Date=>"2023-05-09"}}
  #     ]
  #   }

The original hash h is unchanged, which can be easily verified.

  • Related