【问题标题】:How to extend Ruby Enumerable class max_by to ignore nil?如何扩展 Ruby Enumerable 类 max_by 以忽略 nil?
【发布时间】:2025-11-23 09:05:01
【问题描述】:
a = [4, 3, 2, nil]
a.max_by { |v| v * 2 } => NoMethodError: undefined method `*' for nil:NilClass

如何重载 max_by 以忽略 nil 值?

【问题讨论】:

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


    【解决方案1】:

    在调用 max_by 之前,您可以使用 Array.compact 删除 nil。

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

    【讨论】:

    • 虽然有效,但并不能完全回答 OP 问题(如何扩展 Enumerable 类)。
    【解决方案2】:

    欢迎使用 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.

    【讨论】:

      【解决方案3】:

      这是另一个:

      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]
      

      【讨论】: