【问题标题】:Is it ok to use `any?` to check if an array is not empty?可以使用 `any?` 来检查数组是否为空吗?
【发布时间】:2011-09-08 21:50:46
【问题描述】:

使用any?方法检查数组是否为空是不是很糟糕?

a = [1,2,3]

a.any?
=> true

a.clear

a.any?
=> false

还是使用unless a.empty? 更好?

【问题讨论】:

    标签: ruby arrays


    【解决方案1】:

    any? 在某些情况下与not empty? 不同。

    >> [nil, 1].any?
    => true
    >> [nil, nil].any?
    => false
    

    来自文档:

    如果没有给出块,Ruby 会添加 {|obj| 的隐式块obj}(那个 有吗?如果至少返回 true 集合成员之一不是 false 或 nil)。

    【讨论】:

    • 有没有与empty?相反的功能?
    • @RocketR 你可能想签出present? 方法。
    • @dantastic #present? 仅适用于 Rails。在纯 Ruby 中,你会得到 NoMethodError: undefined method 'present?' for Array
    • 不完全是 Rails-only,Active Support 可以不使用 Rails,只需要 require 'activesupport'
    【解决方案2】:

    将其值评估为true 或为空的数组之间的区别。

    方法empty?来自Array类
    http://ruby-doc.org/core-2.0.0/Array.html#method-i-empty-3F

    它用于检查数组是否包含某些内容。这包括评估为false 的内容,例如nilfalse

    >> a = []
    => []
    >> a.empty?
    => true
    >> a = [nil, false]
    => [nil, false]
    >> a.empty?
    => false
    >> a = [nil]
    => [nil]
    >> a.empty?
    => false
    

    方法any?来自Enumerable模块。
    http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-any-3F

    它用于评估数组中的“任何”值是否为true。 与此类似的方法是 none?all?one?,它们都只是检查可以评估多少次 true。这与在数组中找到的值的计数无关。

    案例一

    >> a = []
    => []
    >> a.any?
    => false
    >> a.one?
    => false
    >> a.all?
    => true
    >> a.none?
    => true
    

    案例2

    >> a = [nil, true]
    => [nil, true]
    >> a.any?
    => true
    >> a.one?
    => true
    >> a.all?
    => false
    >> a.none?
    => false
    

    案例3

    >> a = [true, true]
    => [true, true]
    >> a.any?
    => true
    >> a.one?
    => false
    >> a.all?
    => true
    >> a.none?
    => false
    

    【讨论】:

      【解决方案3】:

      避免any? 用于大型数组。

      • any?O(n)
      • empty?O(1)

      any? 不检查长度,但实际上扫描整个数组以查找真实元素。

      static VALUE
      rb_ary_any_p(VALUE ary)
      {
        long i, len = RARRAY_LEN(ary);
        const VALUE *ptr = RARRAY_CONST_PTR(ary);
      
        if (!len) return Qfalse;
        if (!rb_block_given_p()) {
          for (i = 0; i < len; ++i) if (RTEST(ptr[i])) return Qtrue;
        }
        else {
          for (i = 0; i < RARRAY_LEN(ary); ++i) {
              if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qtrue;
          }
        }
        return Qfalse;
      }
      

      另一方面,empty? 只检查数组的长度。

      static VALUE
      rb_ary_empty_p(VALUE ary)
      {
        if (RARRAY_LEN(ary) == 0)
          return Qtrue;
        return Qfalse;
      }
      

      如果您有以大量 nil 值开头的“稀疏”数组(例如刚刚创建的数组),则差异是相关的。

      【讨论】:

      • 在这个用例中,只有当您有以大量 nil 值开头的“稀疏”数组,以及在第一个元素处没有块返回的“普通”数组 any? 时,差异才是相关的,所以复杂度仍然是 O(1),就像 empty? 方法一样
      【解决方案4】:

      在语句前加上感叹号会让你知道数组是否不为空。所以在你的情况下 -

      a = [1,2,3]
      !a.empty?
      => true
      

      【讨论】:

      • 双重否定?你是认真的吗?
      • 他这么不认真!
      • 呵呵。双重否定并不理想,在这种特定情况下似乎更具可读性。
      • 双重否定是原始问题“检查数组不为空”的一部分。这就回答了这个问题。
      【解决方案5】:

      我会建议使用unlessblank来检查是否为空。

      例子:

      unless a.blank?
        a = "Is not empty"
      end
      

      这将知道“a”是否为空。 如果 'a' 为空,则下面的代码将不会运行。

      【讨论】:

      • #blank? 是 Rails 的一部分。如果他们已经在使用 Rails,那么#present? 就是对#blank? 的否定。
      • 这是一个关于数组而不是字符串的问题。
      【解决方案6】:

      我认为使用any? 一点也不坏。我经常使用它。简洁明了。

      但是,如果您担心所有nil 值都会将其丢弃,那么您实际上是在询问数组是否具有size &gt; 0。在这种情况下,这个死的简单扩展(未优化,猴子风格)会让你接近。

      Object.class_eval do
      
        def size?
          respond_to?(:size) && size > 0
        end
      
      end
      
      > "foo".size?
       => true
      > "".size?
       => false
      > " ".size?
       => true
      > [].size?
       => false
      > [11,22].size?
       => true
      > [nil].size?
       => true
      

      这是相当描述性的,逻辑上是问“这个对象有大小吗?”。而且它很简洁,不需要 ActiveSupport。而且很容易构建。

      需要考虑的一些额外内容:

      1. 这与来自 ActiveSupport 的 present? 不同。
      2. 您可能需要String 的自定义版本,它会忽略空格(就像present? 一样)。
      3. 您可能希望将名称 length? 用于 String 或其他可能更具描述性的类型。
      4. 您可能希望为 Integer 和其他 Numeric 类型自定义它,以便逻辑零返回 false

      【讨论】:

        猜你喜欢
        • 2014-11-14
        • 2015-02-19
        • 2017-09-13
        • 2014-03-19
        • 1970-01-01
        • 1970-01-01
        • 2011-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多