在 Ruby 中链接两个比较 <=> 运算符的任何简单方法?

car*_*yam 3 ruby comparison comparison-operators

Ruby 带有方便的<=>比较运算符,并且原生原始类型支持它们。我想知道是否有一种简单的方法可以将它们组合起来以比较更复杂的对象,例如 Structs。例如,给定

class Datum < Struct.new(:code, :volume); end

datum1 = Datum.new('B',10)
datum2 = Datum.new('A',10)
datum3 = Datum.new('C',11)

data = [datum1, datum2, datum3]
Run Code Online (Sandbox Code Playgroud)

我想排序datavolume,然后如果volumes为相等的,由code。喜欢

data.sort {|a,b| (a.volume <=> b.volume) ??? (a.code <=> b.code)}
Run Code Online (Sandbox Code Playgroud)

我应该放入???什么?

我正在寻找一个解决方案:

  • 避免重新计算 <=>
  • 一个班轮
  • 短的 ;-)

Pat*_*ity 5

对于上面概述的这种简单情况,您可以使用sort_by

data.sort_by {|a| [a.volume, a.code] }
#=> [
#     #<struct Datum code="A", volume=10>,
#     #<struct Datum code="B", volume=10>,
#     #<struct Datum code="C", volume=11>
#   ]
Run Code Online (Sandbox Code Playgroud)

如果您仅按单个属性排序,则它会变得更短:

data.sort_by(&:volume)
#=> [
#     #<struct Datum code="B", volume=10>,
#     #<struct Datum code="A", volume=10>,
#     #<struct Datum code="C", volume=11>
#   ]
Run Code Online (Sandbox Code Playgroud)

where&:volume使用Symbol#to_procand 是proc {|a| a.volume }(类似于 lambda)的简写。

如果您需要使其更复杂(即具有不同的左侧和右侧),您可以将其扩展为调用sort

data.sort {|a,b| [a.volume, a.code] <=> [b.volume, b.code] }
#=> [
#     #<struct Datum code="A", volume=10>,
#     #<struct Datum code="B", volume=10>,
#     #<struct Datum code="C", volume=11>
#   ]
Run Code Online (Sandbox Code Playgroud)

整个事情都有效,因为<=>定义的运算符Array完全符合您的需要,适用于任意级别。