问题 通过升序和降序对多个值进行排序
我正在尝试根据不同的属性对对象数组进行排序。其中一些属性我想按升序排序,有些属性按降序排序。我已经能够按升序或降序排序,但无法将两者结合起来。
这是我正在使用的简单类:
class Dog
attr_reader :name, :gender
DOGS = []
def initialize(name, gender)
@name = name
@gender = gender
DOGS << self
end
def self.all
DOGS
end
def self.sort_all_by_gender_then_name
self.all.sort_by { |d| [d.gender, d.name] }
end
end
然后,我可以实例化一些狗,以便稍后进行分类。
@rover = Dog.new("Rover", "Male")
@max = Dog.new("Max", "Male")
@fluffy = Dog.new("Fluffy", "Female")
@cocoa = Dog.new("Cocoa", "Female")
然后我可以使用sort_all_by_gender_then_name方法。
Dog.sort_all_by_gender_then_name
=> [@cocoa, @fluffy, @max, @rover]
它返回的数组首先包括女性,然后是男性,所有数据都按名称按升序排序。
但是,如果我想让性别下降,然后命名升序,那么它将首先是男性,然后按名称升序排序。在这种情况下:
=> [@max, @rover, @cocoa, @fluffy]
或者,如果我想按性别提升,但名称下降:
=> [@fluffy, @cocoa, @rover, @max]
在对数值进行排序时,可以预先添加 - 以使其反向排序。但是,我一直无法找到使用字符串执行此操作的方法。任何帮助或想法将不胜感激。谢谢。
2920
2018-05-18 20:35
起源
答案:
这是使用它的一种方法 .sort
代替 .sort_by
:
dogs = [
{ name: "Rover", gender: "Male" },
{ name: "Max", gender: "Male" },
{ name: "Fluffy", gender: "Female" },
{ name: "Cocoa", gender: "Female" }
]
# gender asc, name asc
p(dogs.sort do |a, b|
[a[:gender], a[:name]] <=> [b[:gender], b[:name]]
end)
# gender desc, name asc
p(dogs.sort do |a, b|
[b[:gender], a[:name]] <=> [a[:gender], b[:name]]
end)
# gender asc, name desc
p(dogs.sort do |a, b|
[a[:gender], b[:name]] <=> [b[:gender], a[:name]]
end)
输出:
[{:name=>"Cocoa", :gender=>"Female"}, {:name=>"Fluffy", :gender=>"Female"}, {:name=>"Max", :gender=>"Male"}, {:name=>"Rover", :gender=>"Male"}]
[{:name=>"Max", :gender=>"Male"}, {:name=>"Rover", :gender=>"Male"}, {:name=>"Cocoa", :gender=>"Female"}, {:name=>"Fluffy", :gender=>"Female"}]
[{:name=>"Fluffy", :gender=>"Female"}, {:name=>"Cocoa", :gender=>"Female"}, {:name=>"Rover", :gender=>"Male"}, {:name=>"Max", :gender=>"Male"}]
基本上,如果需要按降序排序,通过将属性交换到另一个元素,这类似于否定数字(如您在问题中所提到的)。
13
2018-05-18 20:49
答案:
这是使用它的一种方法 .sort
代替 .sort_by
:
dogs = [
{ name: "Rover", gender: "Male" },
{ name: "Max", gender: "Male" },
{ name: "Fluffy", gender: "Female" },
{ name: "Cocoa", gender: "Female" }
]
# gender asc, name asc
p(dogs.sort do |a, b|
[a[:gender], a[:name]] <=> [b[:gender], b[:name]]
end)
# gender desc, name asc
p(dogs.sort do |a, b|
[b[:gender], a[:name]] <=> [a[:gender], b[:name]]
end)
# gender asc, name desc
p(dogs.sort do |a, b|
[a[:gender], b[:name]] <=> [b[:gender], a[:name]]
end)
输出:
[{:name=>"Cocoa", :gender=>"Female"}, {:name=>"Fluffy", :gender=>"Female"}, {:name=>"Max", :gender=>"Male"}, {:name=>"Rover", :gender=>"Male"}]
[{:name=>"Max", :gender=>"Male"}, {:name=>"Rover", :gender=>"Male"}, {:name=>"Cocoa", :gender=>"Female"}, {:name=>"Fluffy", :gender=>"Female"}]
[{:name=>"Fluffy", :gender=>"Female"}, {:name=>"Cocoa", :gender=>"Female"}, {:name=>"Rover", :gender=>"Male"}, {:name=>"Max", :gender=>"Male"}]
基本上,如果需要按降序排序,通过将属性交换到另一个元素,这类似于否定数字(如您在问题中所提到的)。
13
2018-05-18 20:49
这个 ReversedOrder
mixin可以帮助您完成单独属性的混合方向排序,使用 sort_by
:
module ReversedOrder
def <=>(other)
- super
end
end
使用示例:
dogs = [
{ name: "Rover", gender: "Male" },
{ name: "Max", gender: "Male" },
{ name: "Fluffy", gender: "Female" },
{ name: "Cocoa", gender: "Female" }
]
dogs.sort_by {|e| [e[:gender], e[:name]] }
=> [{:name=>"Cocoa", :gender=>"Female"},
{:name=>"Fluffy", :gender=>"Female"},
{:name=>"Max", :gender=>"Male"},
{:name=>"Rover", :gender=>"Male"}]
dogs.sort_by {|e| [e[:gender].dup.extend(ReversedOrder), e[:name]] }
=> [{:name=>"Max", :gender=>"Male"},
{:name=>"Rover", :gender=>"Male"},
{:name=>"Cocoa", :gender=>"Female"},
{:name=>"Fluffy", :gender=>"Female"}]
注意:小心 dup
逆转的元素。如果没有它,您将把比较逆变器混合到实际物体而不仅仅是制作的钥匙 sort_by
它将永远产生反向比较。
1
2018-05-18 22:07