2016-10-25 2 views
0

Wenn sort_by! Rubys mit einem Multi-Feld Art zu tun, wie können Sie auf Bestellung ändern nur eines der Felder ihrer Sortierung nachSortieren nach: Reihenfolge bei Änderung eines Feldes in mehreren Feldern sortieren

ex:

a = [{:id => 1, :email_type=>"discover", :date=>2016-10-25 12:27:21 -0400}, {:id => 2, :email_type=>"personal", :date=>2016-10-25 12:27:34 -0400}, {:id => 3, :email_type=>"discover", :date=>2016-10-25 12:27:42 -0400}]

a.sort_by! {|e| [e[:email_type], e[:date]]}

kehrt

[{:id => 1, :email_type=>"discover", :date=>2016-10-25 12:27:21 -0400}, {:id => 3, :email_type=>"discover", :date=>2016-10-25 12:27:42 -0400}, {:id => 2, :email_type=>"personal", :date=>2016-10-25 12:27:34 -0400}]

sortiert nach Typ, dann Datum ASC. Allerdings möchte ich Datum DESC

[{:id => 3, :email_type=>"discover", :date=>2016-10-25 12:27:42 -0400}, {:id => 1, :email_type=>"discover", :date=>2016-10-25 12:27:21 -0400}, {:id => 2, :email_type=>"personal", :date=>2016-10-25 12:27:34 -0400}]

wie würde ich das tun?

Antwort

0
arr = [{:id => 1, :email_type=>"discover", :date=>"2016-10-25 12:27:21 -0400"}, 
     {:id => 2, :email_type=>"personal", :date=>"2016-10-25 12:27:34 -0400"}, 
     {:id => 3, :email_type=>"discover", :date=>"2016-10-25 12:27:42 -0400"}] 

Hier sind zwei Möglichkeiten, dies zu tun.

Convert Datum-Zeiten DateTime Objekte, auf Sekunden konvertieren und zu sortieren auf :email_type und negative Sekunden

require 'date' 

arr.sort_by do |h| 
    [h[:email_type], -DateTime.strptime(h[:date], '%Y-%m-%d %H:%M:%S %z').to_time.to_i] 
end  
    #=> [{:id=>3, :email_type=>"discover", :date=>"2016-10-25 12:27:42 -0400"}, 
    # {:id=>1, :email_type=>"discover", :date=>"2016-10-25 12:27:21 -0400"}, 
    # {:id=>2, :email_type=>"personal", :date=>"2016-10-25 12:27:34 -0400"}] 

Baukonstruktion und Anordnung von :email_type Werten in der letzten Bestellung gewünscht, sortiert nach dem Index von dass Array und das Datum-Zeit-String, dann umkehren

email_type_order = arr.map { |h| h[:email_type] }.uniq.sort.reverse 
    #=> ["personal", "discover"] 
arr.sort_by { |h| [email_type_order.index(h[:email_type]), h[:date]] }.reverse 
    #=> [{:id=>3, :email_type=>"discover", :date=>"2016-10-25 12:27:42 -0400"}, 
    # {:id=>1, :email_type=>"discover", :date=>"2016-10-25 12:27:21 -0400"}, 
    # {:id=>2, :email_type=>"personal", :date=>"2016-10-25 12:27:34 -0400"}] 

für Ruby v2.2 + Sie können das vermeiden letzter reverse Betrieb von Enumerable#max_by mit einem Argumente gleich die Größe des Arrays mit:

email_type_order = arr.map { |h| h[:email_type] }.uniq.sort.reverse 
    #=> ["personal", "discover"] 
arr.max_by(arr.size) { |h| [email_type_order.index(h[:email_type]), h[:date]] } 

Bitte beachte, dass wir hier auf dem Datum-Zeit-String (dh ohne Umwandlung in ein DateTime Objekt), weil die Saiten sortieren sind nach Jahr, Monat, Tag, Stunde, Minute, Sekunde und Zeitzone geordnet und die Felder sind links mit Nullen aufgefüllt.

Verwandte Themen