Using Ruby I want to evaluate all items in an array, and return true if they all pass a conditional test.
I can do this using e.g. array.all? { |value| value == 2 }
So:
> array=[2,2]
> array.all? { |value| value == 2 }
=> true
> array=[2,3]
> array.all? { |value| value == 2 }
=> false
Great!
But, why does an empty array pass this test?
> array=[]
> array.all? { |value| value == 2 }
=> true
Shouldn't this return false?
And if I need it to return false, how should I modify the method?
As Amit Kumar Gupta writes, it is the standard interpretation of universal quantification. I have no idea why you expect it to be
false
. Here, you can see it should betrue
by inference.Universal quantification is equivalent to conjunction, thus ("<=>" means equivalent):
Notice that any proposition is equivalent to the conjunction of true and itself, so:
If you lessen the elements in the set to two, you get:
and further to one element:
Now, what happens with the empty set? Naturally,
By noticing that existential quantification is equivalent to disjunction, you can also see that you should expect
false
with existential quantification over an empty set.Since there is no item in the array that FAILS that test, it returns true. So just use somehting like:
Or something like that.
The source of all? method says that it uses static variable(which is initially set to true) and then performs the AND operation between the static variable value and the result of the iteration finally returns this static variable as a result.
as the array is Empty ruby will never iterate on this empty array and as a result of this all? method will return the static variable which was set to true.
This is a vacuous truth. It's the standard interpretation of a universal quantification, i.e. a
over an empty
collection
, but it's known to strike people as counter-intuitive when they first see it in a formal setting. One nice way to think about why this is the preferred semantics is to think about how you would implementall?
.To make your test require that the array is non-empty, just do
Note that
array.any?
is fast no matter how large the array, whereasarray.all? { |x| x == 2 }
can be slow, depending on how bigarray
is and how rare2
is in it. So put thearray.any?
first.Also note, there are degenerate cases where this won't work, for instance if
array
is[nil]
or[false]
. If cases like this might come up, replacearray.any?
witharray.any? { true }
.The documentation says : "The method returns true if the block never returns false or nil.." In the case of an empty array the block never executes and hence the method will always return
true
. As far as returningfalse
is concerned you'll have toarr.empty?
There is no item in that array that doesn't pass the test. I think you may need to throw in a test for array length.