检查数组是否可排序

时间:2018-08-24 19:32:09

标签: ruby-on-rails ruby sorting

在对数组进行排序时是否有避免这种错误的方法?

 ArgumentError: comparison of Hash with Hash failed

我正在寻找这样的东西:

a.sort if a.is_sortable?

2 个答案:

答案 0 :(得分:4)

排序通常基于Comparable

  

Comparable混合用于其对象可以排序的类。该类必须定义<=>运算符,该运算符将接收方与另一个对象进行比较,并根据接收方是小于,等于还是大于另一个对象返回-1、0或+1。

所以你可以看看:

a.grep(Comparable)

,查看其长度是否与a相同。或者你可以说:

a.all? { |e| e.is_a? Comparable } 

但是您实际上并不需要Comparable来使#sort正常工作,您只需要一个<=>方法就可以说:

a.all? { |e| e.respond_to? :<=> }

当然,以上所有条件均假设a的所有元素都与<=>相同(即x <=> y适用于任何两个条目xy中的a),即使a的所有元素都是Comparable或即使它们都对<=>做出响应,也不一定是这种情况。我们还假设<=>的实现是正确的,但是如果您对飞船运算符的实现不正确,那么所有的赌注都不会生效。

对于任意数组a,判断是否可以对其进行排序的唯一方法是尝试对其进行排序并查看其是否爆炸。对于您对元素了解更多的数组(即,元素都是同一类的所有实例),您可以使用一些选择。

答案 1 :(得分:1)

简短的回答:不,没有is_sortable?方法。

长答案:sort使用<=>运算符,因此您可以检查其是否已定义:

a.sort if a.all? { |item| item.respond_to?(:<=>) }

但是它是为哈希定义的,因为它们继承自Kernel

{}.respond_to?(:<=>) # => true
{}.method(:<=>) # => #<Method: Hash(Kernel)#<=>>

但是,当您尝试在散列上使用它时,通常会返回nil,这会导致异常:

# No idea why this should work:
{} <=> {} # => 0
{a: :b} <=> {c: :d} # => nil

因此,如果最好使用sort_by并提出自己的可以处理哈希的排序算法,则可能是最好的选择。