题
我真的很想在不进行猴子修补的情况下处理这个问题,但我还没有找到其他选择。
我有一个数组(在 Ruby 中),我需要按多个条件排序。我知道如何使用排序方法,并且使用了使用选项数组按多个条件进行排序的排序技巧。但是,在这种情况下,我需要第一个条件进行升序排序,第二个条件进行降序排序。例如:
ordered_list = [[1, 2], [1, 1], [2, 1]]
有什么建议么?
编辑:刚刚意识到我应该提到我无法轻松比较第一个值和第二个值(我实际上在这里使用对象属性)。所以对于一个简单的例子来说,它更像是:
ordered_list = [[1, "b"], [1, "a"], [2, "a"]]
解决方案
怎么样:
ordered_list = [[1, "b"], [1, "a"], [2, "a"]]
ordered_list.sort! do |a,b|
[a[0],b[1]] <=> [b[0], a[1]]
end
其他提示
我曾经经历过一场噩梦,试图弄清楚如何对特定属性进行反向排序,但通常对其他两个属性进行排序。只是关于在此之后出现的那些分类的注释,并被| a,b |混淆。块语法。您不能使用 {|a,b| a.blah <=> b.blah}
块样式与 sort_by!
或者 sort_by
. 。它必须与 sort!
或者 sort
. 。另外,正如之前其他海报交换所指出的 a
和 b
跨比较运算符 <=>
反转排序顺序。像这样:
要正常按 blah 和 craw 排序,但按相反顺序按 bleu 排序,请执行以下操作:
something.sort!{|a,b| [a.blah, b.bleu, a.craw] <=> [b.blah, a.bleu, b.craw]}
也可以使用 -
签名与 sort_by
或者 sort_by!
对数字进行反向排序(据我所知,它仅适用于数字,因此不要尝试使用字符串,因为它只会出错并杀死页面)。
认为 a.craw
是一个整数。例如:
something.sort_by!{|a| [a.blah, -a.craw, a.bleu]}
我遇到了同样的基本问题,并通过添加以下内容解决了它:
class Inverter
attr_reader :o
def initialize(o)
@o = o
end
def <=>(other)
if @o.is && other.o.is
-(@o <=> other.o)
else
@o <=> other.o
end
end
end
这是一个简单地反转 <=> 函数的包装器,然后它允许您执行以下操作:
your_objects.sort_by {|y| [y.prop1,Inverter.new(y.prop2)]}
Enumerable#multisort
是一个通用的解决方案,可以应用于数组 任何尺寸, ,不仅仅是那些有 2 项的项目。参数是布尔值,指示特定字段是否应按升序或降序排序(用法如下):
items = [
[3, "Britney"],
[1, "Corin"],
[2, "Cody"],
[5, "Adam"],
[1, "Sally"],
[2, "Zack"],
[5, "Betty"]
]
module Enumerable
def multisort(*args)
sort do |a, b|
i, res = -1, 0
res = a[i] <=> b[i] until !res.zero? or (i+=1) == a.size
args[i] == false ? -res : res
end
end
end
items.multisort(true, false)
# => [[1, "Sally"], [1, "Corin"], [2, "Zack"], [2, "Cody"], [3, "Britney"], [5, "Betty"], [5, "Adam"]]
items.multisort(false, true)
# => [[5, "Adam"], [5, "Betty"], [3, "Britney"], [2, "Cody"], [2, "Zack"], [1, "Corin"], [1, "Sally"]]
我已经使用格伦的食谱有一段时间了。厌倦了一遍又一遍地将代码从一个项目复制到另一个项目,我决定将其作为一个宝石: