【问题标题】:Idiomatic Ruby filter for nil-or-empty?用于 nil-or-empty 的惯用 Ruby 过滤器?
【发布时间】:2012-11-10 02:35:38
【问题描述】:

我正在寻找一种更惯用的方法来过滤掉数组的 nil-or-empty 元素。

我有很多形式的方法:

def joined
    [some_method, some_other_method].compact.reject(&:empty?).join(' - ')
end

这将获取 some_methodsome_other_method 的结果,并仅返回非零(compact 本质上等同于 reject(&:nil?))且非空的结果。

Array 或 Enumerable 中是否有任何东西可以一次性获得相同的结果?

【问题讨论】:

  • 有 activesupport 是,有核心 Ruby 没有。
  • 你的方法真的不应该关心数组中是否有空白值。重构候选人!
  • @padde 为什么不关心?数组只在方法中创建,以避免重复代码。过滤是函数的全部存在理由:取 X 和/或 Y 中的任何一个非零和非空白,并对它们做一些事情(在示例中,用连字符连接它们) .

标签: ruby idioms enumerable


【解决方案1】:

我认为你不需要使用reject 方法。只需使用 Array 的 select 方法即可。

def joined
  [some_method, some_other_method].select { |method| method.present? }
end

甚至更好:

def joined
  [some_method, some_other_method].select(&:present?)
end

欲了解更多Idiomatic way to write Ruby code,您应该阅读此article

【讨论】:

  • select(&:present?) 在我 2012 年接受的答案的第一行中提到,正如当时所指出的,它是 added by ActiveSupport
【解决方案2】:

@trans 很享受我的 +1,但经过进一步考虑,我得出了以下结论。

如果我们假设一切都是Object,那么我们真正需要的只是class Object的补丁

class Object
    def empty?
        self == 0 or not self
    end
end

满足我的要求:

1.9.3 :001 > d=[Object.new, Class, {a:nil}, 'a', '', [], 1, 1.1, 0, 0.0, 0x0, 0E0, true, false, nil]
 => [#<Object:0x007fd56c086918>, Class, {:a=>nil}, "a", "", [], 1, 1.1, 0, 0.0, 0, 0.0, true, false, nil] 
1.9.3 :002 > d.reject(&:empty?)
 => [#<Object:0x007fd56c086918>, Class, {:a=>nil}, "a", 1, 1.1, true] 

你的呢?我们还需要更多东西吗?请通过投票表达您的疑虑或默示同意,以帮助推动上游的语言变革。

开心!

【讨论】:

    【解决方案3】:

    也许我们只需要一个简单的 NilClass 扩展?

    class NilClass
      def empty?
        true
      end
    end
    

    【讨论】:

    • +1 最小占用空间;还可以使用表达式 self == 0 等扩展 Fixnum
    【解决方案4】:

    接受猴子补丁? :)

    你可以试试这个:

    class Array
      def tight
        self.compact.reject { |i| i.size.zero? }
      end
    end
    
    p [nil, 1, ''].tight
    #=> [1]
    p ['', nil, 2].tight
    #=> [2]
    

    它适用于任何响应 size 的对象,而不仅仅是响应 empty? 的对象

    【讨论】:

    • 您可以将== 0 改进为zero?。对size响应而不响应empty?的类有哪些?
    • zero? 是一个很好的改进,但是== 0 对我来说更具可读性/可用性。 Fixnums 不响应empty?
    • 我认为对于大多数人来说zero? 更具可读性。此外,它比== 0更快。
    【解决方案5】:

    下面的代码应该可以解决问题:

    [some_method, some_other_method].reject{|i| i.nil? || i.empty? }
    

    它可以很容易地用于扩展数组类:

    class Array
    
      def purge
        self.reject{|i| i.nil? || i.empty? }
      end 
    
    end
    

    然后你可以这样做:

    [some_method, some_other_method].purge
    

    【讨论】:

    • 这个版本比我在第一个问题中发布的版本要长,这违背了重点。
    • 你的版本是 69 个字符,而 @Eric 的版本只有 64 个字符。
    • 我的版本中的 .join(' - ') 显示了它可能用于什么的示例,将其增加到 76。
    【解决方案6】:

    在 Rails 中,您可以使用 reject(&amp;:blank?),或者等效的 select(&amp;:present?)

    如果这不是针对 Rails 应用程序,并且您经常这样做,我建议您在 String 或您要过滤的任何其他内容上定义自己的帮助程序。

    class String
      alias :blank? :empty?
    end
    
    class NilClass
      def blank?
        true
      end
    end
    

    【讨论】:

    猜你喜欢
    • 2012-08-11
    • 2013-10-27
    • 2015-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多