我想要按字典顺序对我的坐标数组进行排序。但是我不确定如何实现。数组中的每个元素都是一个具有Fixnum
字段#x
和#y
的Coordinate
对象。
我刚接触Ruby并不一定理解排序枚举。会像这样吗?
coordinate_array.sort! { |a,b| a.x <==> b.x && a.y <==> b.y }
首先,宇宙飞船操作符是<=>
而不是<==>
其次,您没有正确组合这两个比较:比较的结果将是-1、0或1。这些都是真值,因此true && foo
就是foo
,所以您的代码只会按y值排序。
您可以像这样编写:
x_ordering = a.x <=> b.x
x_ordering == 0 ? a.y <=> b.y : x_ordering
<=>
,所以你可以直接这样做:array.sort! { |a,b| [a.x, a.y] <=> [b.x, b.y]}
这种方法更加简洁明了,但是每次比较都需要创建两个数组,会稍微消耗一些资源。
你甚至可以这样做:
array.sort_by! { |a| [a.x, a.y] }
这个版本更加清晰,但是内存占用略有不同。它会创建一个由块返回值替换原始值的数组,并使用该数组对原始数组进行排序。
通常情况下我会使用后者,除非我有充分的理由选择另一种方式。
Frederick Cheung的回答已经描述了如何按自定义属性排序。
另一个选项是通过实现Coordinate#<=>
来提供默认的排序顺序:
class Coordinate
# ...
def to_a
[x, y]
end
def <=>(other)
return unless other.is_a? Coordinate
to_a <=> other.to_a
end
end
只需调用:
coordinate_array.sort!
Comparable
mixin,它使用<=>
来实现传统的比较运算符(<
、<=
、==
、>=
和>
)以及方法between?
。Comparable
的引用点赞。 - Cary SwovelandStefan已经描述了如何为您的类实现<=>()
方法。这里是另一种方法:
class Coordinate
attr_reader :x, :y
def to_s
"(#{x}, #{y})"
end
def initialize(x, y)
@x = x
@y = y
end
def <=>(other)
[x, y] <=> [other.x, other.y]
end
end
arr = [
Coordinate.new(1, 2),
Coordinate.new(0, 3),
Coordinate.new(0, 2),
]
puts arr
puts "-" * 10
puts arr.sort!
--output:--
(1, 2)
(0, 3)
(0, 2)
----------
(0, 2)
(0, 3)
(1, 2)
请查看 数组文档了解[1, 1] <=> [1, 0]
的工作原理。