13

我正在尝试根据不同的属性对一组对象进行排序。其中一些属性我想按升序排序,一些按降序排序。我已经能够按升序或降序排序,但无法将两者结合起来。

这是我正在使用的简单类:

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]

对数值进行排序时,您可以在前面加上 - 以使其反向排序。但是,我一直无法找到使用字符串执行此操作的方法。任何帮助或想法将不胜感激。谢谢。

4

2 回答 2

20

这是使用.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"}]

基本上,这类似于否定数字(正如您在问题中提到的那样),如果需要按降序排序,则通过将属性交换到另一个元素。

于 2013-05-18T20:49:08.397 回答
1

这个ReversedOrdermixin 可以帮助你完成单独属性的混合方向排序,使用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它将永远产生反向比较。

于 2013-05-18T22:07:10.263 回答