-3

I want to sort an array of hashes in which each hash has two attributes created_time and updated_time. And the value of these attributes may be either a datestring or nil. I want it to sort by created_time(ASC) first and updated_time(ASC).I tried with sort_by method and I could not specify the condition for multiple keys like sort method suggested in this discussion .

The two attributes created_time and updated_time should be sorted in ascending order with null values as last

Suppose if the array is

[
 {"created_time" => nil, "updated_time" => "2016-04-10"},
 {"created_time" => nil, "updated_time" => "2016-04-09"},
 {"created_time" => "2016-04-15", "updated_time" => nil}
]

I want the result as

[
 {"created_time"=>"2016-04-15", "updated_time"=>nil}, 
 {"created_time"=>nil, "updated_time"=>"2016-04-09"}, 
 {"created_time"=>nil, "updated_time"=>"2016-04-10"}
]

What to do?

Community
  • 1
  • 1
Magesh
  • 427
  • 3
  • 12
  • 2
    if you have tried something, post it here, if there is problem, someone can identify it. dont jus say you tried and didnt work. show what you tried and ask why it didnt work , or where you are stuck! – Ccr Apr 15 '16 at 05:43
  • 1
    Question not fully specified. Where do you want to place the items with `nil` values within the sorted list? – sawa Apr 15 '16 at 05:56
  • @sawa I want to push the nil values to the end of the sorted list – Magesh Apr 15 '16 at 05:58
  • Magesh, that's still not clear. Suppose you have pairs `[ct,nil]`, `[nil, ut]` and `[nil,nil]`. I understand these are to at the end of the sorted array, but how are they to be ordered among themselves? – Cary Swoveland Apr 15 '16 at 06:57
  • @Cary Both of them have to be sorted in ascending order with nulls last – Magesh Apr 15 '16 at 07:04
  • I asked how three pairs (each containing one or two `nil`s) are to be ordered (and be placed at the end of the sorted array). I don't understand what you mean by "both" in your reply. Also, you've edited your question to provide an example in which each hash contains one `nil` value. Are there not hashes for which no values are `nil`? Incidentally, `nil` is not "null". – Cary Swoveland Apr 15 '16 at 15:41

2 Answers2

0

Suppose arr is an array of hashes {"created_time"=>ct, "updated_time"=>ut}, where ct (ut) is either a datestring with fomat " yyyy-mm-dd" or nil. Let far_away_time be a datestring that is guaranteed to be later than any datestring value of ct or ut. For example, far_away_time = "3000-01-01". Then you can sort using Enumerable #sort_by as follows:

arr.sort_by do |h|
  ct, ut = h.values
  case [ct.nil?, ut.nil?]
  when [true, true]  then [far_away_time, far_away_time, far_away_time]
  when [true, false] then [far_away_time, far_away_time, ut]
  when [false, true] then [far_away_time, ct, far_away_time]
  else [ct, ut, ""]
  end
end

Since the datestrings are in ISO 8601 format, there is no need to convert them to Date objects (i.e., the strings themselves can be sorted). For example, "2016-03-12" < "2016-03-13" #=> true. See the doc for Array#<=> for an explanation of how arrays are ordered.

I am sorting be a three-element array in order that the hashes {"created_time"=>"2016-01-01", "updated_time"=>nil}, {"created_time"=>nil, "updated_time"=>"2016-01-01"} and {"created_time"=>nil, "updated_time"=>nil} are ordered as I have listed them (and placed at the end of the sorted array).

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
0

Sorry for the lack of clarity in the question. I just wanted to sort an array of hashes with two keys in ascending order which can have nil values.And I figured out the way

     def date_time datestring
      DateTime.parse(datestring)
     end

    result = array_to_sort.sort do |a,b|  
     (a["created_time"] && b["created_time"] && a["updated_time"] && b["updated_time"]) ? [ date_time(a["created_time"]), date_time(a["updated_time"])] <=>  [ date_time(b["created_time"]), date_time(b["updated_time"])] : [ a["created_time"] && b["created_time"] ? date_time(a["created_time"]) : a["created_time"] ? -1 : 1,  a["updated_time"] && b["updated_time"] ? date_time(a["updated_time"]) : a["updated_time"] ? -1 : 1] <=>  [ a["created_time"] && b["created_time"] ? date_time(b["created_time"]) : b["created_time"] ? -1 : 1,  a["updated_time"] && b["updated_time"] ? date_time(b["updated_time"]) : b["updated_time"] ? -1 : 1]
    end
Magesh
  • 427
  • 3
  • 12