当使用ruby的sort_by!
进行多字段排序时,如何更改为按其排序的其中一个字段的排序
例如:
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]]}
返回
[{: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}]
按类型排序,然后按日期ASC。但是我想要日期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}]
我该怎么做?
答案 0 :(得分: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"}]
这有两种方法。
将日期时间转换为DateTime
个对象,转换为秒数并按:email_type
排序,负数为秒
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"}]
按所需最终顺序构造:email_type
值的数组,按该数组的索引和日期时间字符串排序,然后反向
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"}]
对于Ruby v2.2 +,您可以使用Enumerable#max_by并使用等于数组大小的参数来避免最终的reverse
操作:
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]] }
请注意,在这里我们可以对日期时间字符串进行排序(即,不将其转换为DateTime
对象)因为字符串按年,月,日,小时,分钟,秒和时区排序,字段用零填充。