如何将Ruby Enumerable类max_by扩展为忽略nil?

时间:2012-06-25 04:51:28

标签: ruby extension-methods overloading ruby-1.9.3 enumerator

a = [4, 3, 2, nil]
a.max_by { |v| v * 2 } => NoMethodError: undefined method `*' for nil:NilClass

如何重载max_by以忽略nil值?

3 个答案:

答案 0 :(得分:8)

在致电max_by之前,您可以使用Array.compact删除nils。

a.compact.max_by { |v| v * 2 }

答案 1 :(得分:4)

欢迎使用Ruby:有很多方法可以解决这个问题!

一个非常简单的解决方案是:

a.max_by { |v| v.to_f * 2 }

因为nil强制浮动为0.这不会处理负值,但是因为nil只是一个名为NilClass的类的单个实例,现在和Ruby中的所有类一样,我们可以打开它让它学习一点点数学:

class NilClass
  # overloading * operator
  def *(y)
    # returning negative infinity: Ruby 1.8.7
    -1.0/0.0
    # returning negative infinity: Ruby 1.9.2
    # -Float::INFINITY
  end
end

现在我们有了

a.max_by { |v| v * 2 }

返回4。

答案 2 :(得分:2)

这是另一个:

a.max_by { |v| v.nil? ? -Float::INFINITY : v }
#=> 4

对于您的示例,这显然比compact更复杂,但如果您想对数组进行排序并保留nil值,则这是一个方便的技巧。或者如果你想以一种奇怪的方式排序,比如最后的零:

[0,4,5,6,1,9].sort_by { |v| v.zero? ? Float::INFINITY : v }
#=> [1, 4, 5, 6, 9, 0]