Is it ok to use `any?` to check if an array is not empty?
Is it bad to check if an array is not empt开发者_如何学JAVAy by using any?
method?
a = [1,2,3]
a.any?
=> true
a.clear
a.any?
=> false
Or is it better to use unless a.empty?
?
any?
isn't the same as not empty?
in some cases.
>> [nil, 1].any?
=> true
>> [nil, nil].any?
=> false
From the documentation:
If the block is not given, Ruby adds an implicit block of {|obj| obj} (that is any? will return true if at least one of the collection members is not false or nil).
The difference between an array evaluating its values to true
or if its empty.
The method empty?
comes from the Array class
http://ruby-doc.org/core-2.0.0/Array.html#method-i-empty-3F
It's used to check if the array contains something or not. This includes things that evaluate to false
, such as nil
and false
.
>> a = []
=> []
>> a.empty?
=> true
>> a = [nil, false]
=> [nil, false]
>> a.empty?
=> false
>> a = [nil]
=> [nil]
>> a.empty?
=> false
The method any?
comes from the Enumerable module.
http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-any-3F
It's used to evaluate if "any" value in the array evaluates to true
.
Similar methods to this are none?
, all?
and one?
, where they all just check to see how many times true could be evaluated. which has nothing to do with the count of values found in a array.
case 1
>> a = []
=> []
>> a.any?
=> false
>> a.one?
=> false
>> a.all?
=> true
>> a.none?
=> true
case 2
>> a = [nil, true]
=> [nil, true]
>> a.any?
=> true
>> a.one?
=> true
>> a.all?
=> false
>> a.none?
=> false
case 3
>> a = [true, true]
=> [true, true]
>> a.any?
=> true
>> a.one?
=> false
>> a.all?
=> true
>> a.none?
=> false
Avoid any?
for large arrays.
any?
isO(n)
empty?
isO(1)
any?
does not check the length but actually scans the whole array for truthy elements.
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?
on the other hand checks the length of the array only.
static VALUE
rb_ary_empty_p(VALUE ary)
{
if (RARRAY_LEN(ary) == 0)
return Qtrue;
return Qfalse;
}
The difference is relevant if you have "sparse" arrays that start with lots of nil
values, like for example an array that was just created.
Prefixing the statement with an exclamation mark will let you know whether the array is not empty. So in your case -
a = [1,2,3]
!a.empty?
=> true
I'll suggest using unless
and blank
to check is empty or not.
Example :
unless a.blank?
a = "Is not empty"
end
This will know 'a' empty or not. If 'a' is blank then the below code will not run.
I don't think it's bad to use any?
at all. I use it a lot. It's clear and concise.
However if you are concerned about all nil
values throwing it off, then you are really asking if the array has size > 0
. In that case, this dead simple extension (NOT optimized, monkey-style) would get you close.
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
This is fairly descriptive, logically asking "does this object have a size?". And it's concise, and it doesn't require ActiveSupport. And it's easy to build on.
Some extras to think about:
- This is not the same as
present?
from ActiveSupport. - You might want a custom version for
String
, that ignores whitespace (likepresent?
does). - You might want the name
length?
forString
or other types where it might be more descriptive. - You might want it custom for
Integer
and otherNumeric
types, so that a logical zero returnsfalse
.
精彩评论