Implementing .all() for a list of booleans? - python

Numpy has a great method .all() for arrays of booleans, that tests if all the values are true. I'd like to do the same without adding numpy to my project. Is there something similar in the standard libary? Otherwise, how would you implement it?
I can of course think of the obvious way to do it:
def all_true(list_of_booleans):
for v in list_of_booleans:
if not v:
return False
return True
Is there a more elegant way, perhaps a one-liner?

There is; it is called all(), surprisingly. It is implemented exactly as you describe, albeit in C. Quoting the docs:
Return True if all elements of the iterable are true (or if the
iterable is empty). Equivalent to:
def all(iterable):
for element in iterable:
if not element:
return False
return True
New in version 2.5.
This is not limited to just booleans. Note that this takes an iterable; passing in a generator expression means only enough of the generator expression is going to be evaluated to test the hypothesis:
>>> from itertools import count
>>> c = count()
>>> all(i < 10 for i in c)
False
>>> next(c)
11
There is an equivalent any() function as well.

There is a similar function, called all().

Related

Python any() function does not act as expected for list of negative numbers

I am trying to compare a list of numbers in an if statement with the any() function. I am using python 3.6 in Spyder. The code in question is:
if any(lst) >= 1:
do_some_stuff
lst is actually generated by list(map(my_func, other_lst)) but after diagnosing my problem I get two behaviors as shown below with my actual lst passed to the any() function:
any([1.535, 1.535, 1.535]) >= 1
>>True
Which is expected.
any([-0.676, -0.676, -0.676]) >= 1
>>True
Which is not expected.
I've delved deeper and found that any number I can put in lst that is less than 0 yields True in my if statement. Also, converting the 1 to a float doesn't help. After reading "truth value testing", this post, and extensive time trying to learn the behavior within my program, I am at a loss. Please help, I am pretty new to python. Thanks!
You are comparing the wrong thing. You are comparing the result of any to 1.
any(mylist) will return true if any element of the list is nonzero. True is greater than or equal to 1.
So this
any(mylist)>=1
is equivalent to just
any(mylist)
What you mean is
any(x>=1 for x in mylist)
Please read the documentation:
any(iterable)
Return True if any element of the iterable is true. If
the iterable is empty, return False. Equivalent to:
def any(iterable):
for element in iterable:
if element:
return True
return False
All your any() expression listed will return True, and you are comparing True with 1, that is True.

Python iterator over string using keyword in

I recently came across some python code I don't understand completely.
s = "abcdef"
x = "bde"
it = iter(s)
print all(c in it for c in x)
I understand that this code checks if x is a subsequence of s. Can someone explain or point me towards an article that explains what's exactly happening at c in it. What is calling the next method of iterator it?
It’s good to start with reading the documentation for the built-in function all():
Return True if all elements of the iterable are true (or if the iterable is empty).
That means that c in it for c in x is a “generator expression”: it produces values. The values it produces are of the boolean expression c in it (see the in operator) for all characters c in string x.
Here, the in operator is responsible for advancing the iterator. Note, however, that the True result is probably lucky. The iterator it can advance only once and because x = "bde" contains the letters in the same sequence as they appear in s = "abcdef", the whole expression works out to the expected result True. Reverse x = "edb" and the expression is False because the iterator is exhausted.

Is any() evaluated lazily?

I am writing a script in which i have to test numbers against a number of conditions. If any of the conditions are met i want to return True and i want to do that the fastest way possible.
My first idea was to use any() instead of nested if statements or multiple or linking my conditions. Since i would be satisfied if any of the conditions were True i could really benefit from any() being lazy and returning True as soon as it could.
Based on the fact that the following print happens instantly and not after 10 (= 0 + 1 + 2 + 3 + 4) seconds i assume it is. Is that the case or am i somehow mistaken?
import time
def some(sec):
time.sleep(sec)
return True
print(any(some(x) for x in range(5)))
Yes, any() and all() short-circuit, aborting as soon as the outcome is clear: See the docs:
all(iterable)
Return True if all elements of the iterable are true (or if the
iterable is empty). Equivalent to:
def all(iterable):
for element in iterable:
if not element:
return False
return True
any(iterable)
Return True if any element of the iterable is true. If the iterable is
empty, return False. Equivalent to:
def any(iterable):
for element in iterable:
if element:
return True
return False
While the all() and any() functions short-circuit on the first "true" element of an iterable, the iterable itself may be constructed in a non-lazy way. Consider this example:
>> any(x == 100 for x in range(10**8))
True
This will take several seconds to execute in Python 2 as range(10**8) constructs a list of 10**8 elements. The same expression runs instantly in Python 3, where range() is lazy.
As Tim correctly mentioned, any and all do short-circuit, but in your code, what makes it lazy is the use of generators. For example, the following code would not be lazy:
print(any([slow_operation(x) for x in big_list]))
The list would be fully constructed and calculated, and only then passed as an argument to any.
Generators, on the other hand, are iterables that calculate each item on demand. They can be expressions, functions, or sometimes manually implemented as lazy iterators.
Yes, it's lazy as demonstrated by the following:
def some(x, result=True):
print(x)
return result
>>> print(any(some(x) for x in range(5)))
0
True
>>> print(any(some(x, False) for x in range(5)))
0
1
2
3
4
False
In the first run any() halted after testing the first item, i.e. it short circuited the evaluation.
In the second run any() continued testing until the sequence was exhausted.
Yes, and here is an experiment that shows it even more definitively than your timing experiment:
import random
def some(x):
print(x, end = ', ')
return random.random() < 0.25
for i in range(5):
print(any(some(x) for x in range(10)))
typical run:
0, 1, 2, True
0, 1, True
0, True
0, 1, 2, 3, True
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, False
No. All and Any support shortcircuiting but they don't make the conditionals interpretation lazy.
If you want an All or Any using lazy evaluation you need to pass them a generator. Or else the values get evaluated in the moment the list/set/iterator/whatever is constructed
JoshiRaez is the actual correct answer.
Here is an example
a = []
any([True, a[0]])
will fail
On the other side, using OR (or AND) will not fail since its not a function:
a = []
True or a[0]

What is the most pythonic way to use len on a scalar?

I read this question
python: how to identify if a variable is an array or a scalar
but when using the following code I get a false on an np.array as can be demonstrated below.
import collections
isinstance(np.arange(10), collections.Sequence)
# returns false
I find it a bit annoying that I can't do len(1) and simply get 1.
The only work around I can think of is a try except statement such as the following:
a = 1
try:
print len(a)
except TypeError:
print 1
Is there a more Pythonic way to do this?
collections.Sequence only applies to sequence objects, which are a very specific type of iterable object. Incidentally, a numpy.ndarray (which is returned by numpy.arange) is not a sequence.
You need to test for either collections.Iterable, which represents any iterable object:
>>> isinstance([1, 2, 3], collections.Iterable)
True
>> isinstance(np.arange(10), collections.Iterable)
True
>>> isinstance(1, collections.Iterable)
False
>>>
or collections.Sized, which represents any object that works with len:
>>> isinstance([1, 2, 3], collections.Sized)
True
>>> isinstance(np.arange(10), collections.Sized)
True
>>> isinstance(1, collections.Sized)
False
>>>
You can then use a conditional expression or similar to do what you want:
print len(a) if isinstance(a, collections.Iterable) else 1
print len(a) if isinstance(a, collections.Sized) else 1
For a complete list of the available abstract base classes in the collections module, see Collections Abstract Base Classes in the Python docs.
I'll just throw in another potential option:
length = getattr(obj, '__len__', lambda:1)()
So get either the __len__ method from the object, or a function that always returns 1, then call it to get your result.
I wouldn't say it's Pythonic, but avoids an import and exception handling. However, I'd still go with comparing if it's a collections.Sized and a conditional statement and put it in a helper function called len_or_1 or something.
Although this isn't pythonic as it uses numpy here is another neat way to make this work:
import numpy as np
a = 1
aSh = np.shape(a)
if len(aSh) == 0:
print 1
else:
print max(aSh)
which gives a behaviour that should work with scalars, lists and matrices.

Behaviour of Python all() operator [duplicate]

This question already has answers here:
Python "all" function with conditional generator expression returning True. Why?
(2 answers)
Closed 9 years ago.
have a question on all() operator in Python.
say
array = ["one","one","one"]
all( x=="one" for x in array ) <<--- i want to check for all "one" in array
The above seem to work. however, if i have
array = []
all( x=="one" for x in array ) <<--- this still return true to me.
The behaviour is that i want it return false if all items are not "one". How to do it? thanks
You can read all() as if it means:
It returns False if any of the items evaluates to False. True otherwise.
So an empty set will return True, because there is none that will make it false.
Generally speaking, in an empty set, all the elements fullfill any requirement you can imagine. That's a principle of logic, not of Python, BTW.
all's implementation is equivalent to this
def all(iterable):
for element in iterable:
if not element:
return False
return True
So, it returns True till any of the elements in the iterable is Falsy. In your case that didnt happen. Thats why it returns True
all always returns True for an empty list/tuple/etc. This is because, technically, every item in an empty collection fulfills any and every condition there is.
To fix the problem, you need to add some additional code to test whether your list is empty or not. Fortunately, empty lists evaluate to False in Python, so you can just do this:
>>> array = []
>>> bool(array and all(x=="one" for x in array))
False
>>> if array and all(x=="one" for x in array):
... print True
... else:
... print False
...
False
>>>
How to do it?
array and all(x=="one" for x in array)
Empty lists are false, so the result is false and it doesn't matter that the all part is true.
If you want to deal with iterables other than containers like list then it's a bit harder. I suppose you need something like this:
set(x=="one" for x in iterable) == { True }
Although if you care about speed, the following should be faster on the whole, since the version above doesn't short-circuit like all does:
def nonempty_all(iterable):
iterator = iter(iterable)
try:
if not next(iterator):
return False
except StopIteration:
return False
return all(iterator)

Categories

Resources