-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?

6
  • 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! Commented Apr 15, 2016 at 5:43
  • 1
    Question not fully specified. Where do you want to place the items with nil values within the sorted list? Commented Apr 15, 2016 at 5:56
  • @sawa I want to push the nil values to the end of the sorted list Commented Apr 15, 2016 at 5: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? Commented Apr 15, 2016 at 6:57
  • @Cary Both of them have to be sorted in ascending order with nulls last Commented Apr 15, 2016 at 7:04

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

Comments

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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.