How do I know if my list has all 1s?
Question:
I am looking for a better way, may be using list comprehensions?
>>> x = [1, 1, 1, 1, 1, 1]
>>> x
[1, 1, 1, 1, 1, 1]
>>> for i in x:
... if i!=1:
... print "fail"
...
>>>
>>> x = [1, 1, 1, 1, 1, 0]
>>> for i in x:
... if i!=1:
... print "fail"
...
fail
>>>
Answers:
>>> x = [1, 1, 1, 1, 1, 1]
>>> all(el==1 for el in x)
True
This uses the function all
with a generator expression.
If you always have only zeroes and ones in the list (or if you want to just check if the list doesn’t have any zeroes), then just use all
without any additional tricks:
>>> x = [1, 0, 1, 1, 1, 0]
>>> all(x)
False
Benchmark of some solutions:
The numbers mean what time in milliseconds it took to run the solution once (average of 1000 timeit
runs)
Python 3.2.3
all(el==1 for el in x): 0.0003 0.0008 0.7903 0.0804 0.0005 0.0006
x==[1]*len(x): 0.0002 0.0003 0.0714 0.0086 0.0045 0.0554
not([1 for y in x if y!=1]): 0.0003 0.0005 0.4142 0.1117 0.1100 1.1630
set(x).issubset({1}): 0.0003 0.0005 0.2039 0.0409 0.0476 0.5310
y = set(x); len(y)==1 and y.pop()==1: WA 0.0006 0.2043 0.0517 0.0409 0.4170
max(x)==1==min(x): RE 0.0006 0.4574 0.0460 0.0917 0.5466
tuple(set(x))==(1,): WA 0.0006 0.2046 0.0410 0.0408 0.4238
not(bool(filter(lambda y: y!=1, x))): WA WA WA 0.0004 0.0004 0.0004
all(x): 0.0001 0.0001 0.0839 WA 0.0001 WA
Python 2.7.3
all(el==1 for el in x): 0.0003 0.0008 0.7175 0.0751 0.0006 0.0006
x==[1]*len(x): 0.0002 0.0003 0.0741 0.0110 0.0094 0.1015
not([1 for y in x if y!=1]): 0.0001 0.0003 0.3908 0.0948 0.0954 0.9840
set(x).issubset({1}): 0.0003 0.0005 0.2084 0.0422 0.0420 0.4198
y = set(x); len(y)==1 and y.pop()==1: WA 0.0006 0.2083 0.0421 0.0418 0.4178
max(x)==1==min(x): RE 0.0006 0.4568 0.0442 0.0866 0.4937
tuple(set(x))==(1,): WA 0.0006 0.2086 0.0424 0.0421 0.4202
not(bool(filter(lambda y: y!=1, x))): 0.0004 0.0011 0.9809 0.1936 0.1925 2.0007
all(x): 0.0001 0.0001 0.0811 WA 0.0001 WA
[PyPy 1.9.0] Python 2.7.2
all(el==1 for el in x): 0.0013 0.0093 0.4148 0.0508 0.0036 0.0038
x==[1]*len(x): 0.0006 0.0009 0.4557 0.0575 0.0177 0.1368
not([1 for y in x if y!=1]): 0.0009 0.0015 175.10 7.0742 6.4390 714.15 # No, this wasn't run 1000 times. Had to time it separately.
set(x).issubset({1}): 0.0010 0.0020 0.0657 0.0138 0.0139 0.1303
y = set(x); len(y)==1 and y.pop()==1: WA 0.0011 0.0651 0.0137 0.0137 0.1296
max(x)==1==min(x): RE 0.0011 0.5892 0.0615 0.1171 0.5994
tuple(set(x))==(1,): WA 0.0014 0.0656 0.0163 0.0142 0.1302
not(bool(filter(lambda y: y!=1, x))): 0.0030 0.0081 0.2171 0.0689 0.0680 0.7599
all(x): 0.0011 0.0044 0.0230 WA 0.0013 WA
The following test cases were used:
[] # True
[1]*6 # True
[1]*10000 # True
[1]*1000+[2]*1000 # False
[0]*1000+[1]*1000 # False
[random.randint(1, 2) for _ in range(20000)] # False
WA
means that the solution gave a wrong answer; RE
stands for runtime error.
So my verdict is, Winston Ewert‘s x==[1]*len(x)
solution is the fastest in most cases. If you rarely have lists of all ones (the data is random, etc.) or you don’t want to use additional RAM, my solution works better. If the lists are small, the difference is negligible.
Some console examples using all()
‘s cousin any()
:
In [4]: x = [1, 1, 1, 1, 1, 1]
In [5]: not any(i!=1 for i in x)
Out[5]: True
In [6]: x = [1, 1, 1, 1, 1, 0]
In [7]: not any(i!=1 for i in x)
Out[7]: False
In addition to the all()
answer already provided, you can also do it with set()
:
>>> x = [1, 1, 1, 1, 1, 1]
>>> y = set(x)
>>> len(y) == 1 and y.pop() == 1
True
>>> a = [1, 1, 1, 1, 0]
>>> b = set(a)
>>> len(b) == 1 and b.pop() == 1
False
Caveat; (and Redeeming Factor):
- As some have pointed out, this is less readable; however…
- I’ll leave this up since:
- As the results in @WinstonEwert’s answer demonstrate, this solution can perform better than the
all()
solution proposed by @BlaXpirit
- I think most members of StackOverflow prefer to learn new things; alternative solutions contribute to that end by prompting discussion, inquiry, and analysis.
This goes through the list and collects any terms that aren’t 1. If those terms exist, then bool returns True and the answer is False.
not(bool(filter(lambda y: y!=1, x)))
@sampson-chen had a good idea that could use some help. Consider up voting his answer and look at this this as an extended comment. (I don’t know how to make code look good in a comment). Here’s my rewrite:
>>> setone = set([1])
>>> x = [1, 1, 1, 1, 1, 1]
>>> set(x) == setone
True
This code does not exactly match the original question because it returns False
for an empty list which could be good or bad but probably doesn’t matter.
Edit
Based on community feedback (thanks @Nabb), here is a second rewrite:
>>> x = [1, 1, 1, 1, 1, 1]
>>> set(x).issubset({1})
This properly handles the case where x is an empty list.
I think this is readable. And the variant part is faster as written (almost twice as fast). In fact, on my Python 2.7 system, it’s always faster for lists up to 20 elements and for lists that are all 1’s. (Up to 3 times faster.)
Update: Vacuous Truth and Reduction of an Empty List
@Peter Olson wrote in a comment:
If the list is empty, then proposition “every element of the list equals one” is vacuously true.
Further discussion in the comments lead up to @sampson-chen writing:
I felt that it ought to be vacuously false; maybe someone in this post will eventually enlighten us on the semantics. – sampson-chen
Let’s see what Python thinks:
>>> all([])
True
Well then how about:
>>> any([])
False
So why is that right? If you haven’t run into this before it might be confusing. There’s a way to think about that may help you understand and remember.
Let’s back up a little bit and start with:
>>> sum(mylist)
Python’s built-in function sum
sums items of an iterable from left to right and returns the total. Thinking more abstractly, sum
reduces an iterable by applying the addition operator.
>>> sum([])
0
The sum of nothing is 0. That’s fairly intuitive. But what about this:
>>> product([])
Okay, it actually returns a name error because product
doesn’t exist as a built-in function. But what should it return? 0? No, the value of an empty product is 1. That’s most mathematically consistent (click the link for a full explanation), because 1 is the identity element for multiplication. (Remember sum([])
returned 0, the identity element for addition.)
Taking this understanding of the special role the identity element plays, and returning to the original problem:
all([])
Is equivalent to reducing the list using the Boolean and
operator. The identity element for and
is True, so the result for the empty list is True
.
any([])
The identity element for or
is False
, the same as the value of this expression.
Yet more possible methods:
x == [1] * len(x)
list(set(x)) == [1]
tuple(set(x)) == (1,)
Some timing results:
all(el==1 for el in x) [1.184262990951538, 1.1856739521026611, 1.1883699893951416]
y = set(x);len(y) == 1 and y.pop() == 1 [0.6140780448913574, 0.6152529716491699, 0.6156158447265625]
set(x) == set([1]) [0.8093318939208984, 0.8106880187988281, 0.809283971786499]
not(bool(filter(lambda y: y!=1, x))) [1.615243911743164, 1.621769905090332, 1.6134231090545654]
not any(i!=1 for i in x) [1.1321749687194824, 1.1325697898864746, 1.132157802581787]
x == [1]*len(x) [0.3790302276611328, 0.3765430450439453, 0.3812289237976074]
list(set(x)) == [1] [0.9047720432281494, 0.9006211757659912, 0.9024860858917236]
tuple(set(x)) == (1,) [0.6586658954620361, 0.6594271659851074, 0.6585478782653809]
And on PyPy because: why not?
all(el==1 for el in x) [0.40866899490356445, 0.5661730766296387, 0.45672082901000977]
y = set(x);len(y) == 1 and y.pop() == 1 [0.6929471492767334, 0.6925959587097168, 0.6805419921875]
set(x) == set([1]) [0.956063985824585, 0.9526000022888184, 0.955935001373291]
not(bool(filter(lambda y: y!=1, x))) [0.21160888671875, 0.1965351104736328, 0.19921493530273438]
not any(i!=1 for i in x) [0.44970107078552246, 0.509315013885498, 0.4380669593811035]
x == [1]*len(x) [0.5422029495239258, 0.5407819747924805, 0.5440030097961426]
list(set(x)) == [1] [1.0170629024505615, 0.9520189762115479, 0.940842866897583]
tuple(set(x)) == (1,) [0.9174900054931641, 0.9112720489501953, 0.9102160930633545]
how about this :
lo = min(L)
hi = max(L)
if (lo != 1) and (hi != 1) and (lo != hi):
print "fail"
Yet another way is:
arr = [1,1,1,1]
len(arr) == sum(arr) #True if arr is all 1's
I am looking for a better way, may be using list comprehensions?
>>> x = [1, 1, 1, 1, 1, 1]
>>> x
[1, 1, 1, 1, 1, 1]
>>> for i in x:
... if i!=1:
... print "fail"
...
>>>
>>> x = [1, 1, 1, 1, 1, 0]
>>> for i in x:
... if i!=1:
... print "fail"
...
fail
>>>
>>> x = [1, 1, 1, 1, 1, 1]
>>> all(el==1 for el in x)
True
This uses the function all
with a generator expression.
If you always have only zeroes and ones in the list (or if you want to just check if the list doesn’t have any zeroes), then just use all
without any additional tricks:
>>> x = [1, 0, 1, 1, 1, 0]
>>> all(x)
False
Benchmark of some solutions:
The numbers mean what time in milliseconds it took to run the solution once (average of 1000 timeit
runs)
Python 3.2.3
all(el==1 for el in x): 0.0003 0.0008 0.7903 0.0804 0.0005 0.0006
x==[1]*len(x): 0.0002 0.0003 0.0714 0.0086 0.0045 0.0554
not([1 for y in x if y!=1]): 0.0003 0.0005 0.4142 0.1117 0.1100 1.1630
set(x).issubset({1}): 0.0003 0.0005 0.2039 0.0409 0.0476 0.5310
y = set(x); len(y)==1 and y.pop()==1: WA 0.0006 0.2043 0.0517 0.0409 0.4170
max(x)==1==min(x): RE 0.0006 0.4574 0.0460 0.0917 0.5466
tuple(set(x))==(1,): WA 0.0006 0.2046 0.0410 0.0408 0.4238
not(bool(filter(lambda y: y!=1, x))): WA WA WA 0.0004 0.0004 0.0004
all(x): 0.0001 0.0001 0.0839 WA 0.0001 WA
Python 2.7.3
all(el==1 for el in x): 0.0003 0.0008 0.7175 0.0751 0.0006 0.0006
x==[1]*len(x): 0.0002 0.0003 0.0741 0.0110 0.0094 0.1015
not([1 for y in x if y!=1]): 0.0001 0.0003 0.3908 0.0948 0.0954 0.9840
set(x).issubset({1}): 0.0003 0.0005 0.2084 0.0422 0.0420 0.4198
y = set(x); len(y)==1 and y.pop()==1: WA 0.0006 0.2083 0.0421 0.0418 0.4178
max(x)==1==min(x): RE 0.0006 0.4568 0.0442 0.0866 0.4937
tuple(set(x))==(1,): WA 0.0006 0.2086 0.0424 0.0421 0.4202
not(bool(filter(lambda y: y!=1, x))): 0.0004 0.0011 0.9809 0.1936 0.1925 2.0007
all(x): 0.0001 0.0001 0.0811 WA 0.0001 WA
[PyPy 1.9.0] Python 2.7.2
all(el==1 for el in x): 0.0013 0.0093 0.4148 0.0508 0.0036 0.0038
x==[1]*len(x): 0.0006 0.0009 0.4557 0.0575 0.0177 0.1368
not([1 for y in x if y!=1]): 0.0009 0.0015 175.10 7.0742 6.4390 714.15 # No, this wasn't run 1000 times. Had to time it separately.
set(x).issubset({1}): 0.0010 0.0020 0.0657 0.0138 0.0139 0.1303
y = set(x); len(y)==1 and y.pop()==1: WA 0.0011 0.0651 0.0137 0.0137 0.1296
max(x)==1==min(x): RE 0.0011 0.5892 0.0615 0.1171 0.5994
tuple(set(x))==(1,): WA 0.0014 0.0656 0.0163 0.0142 0.1302
not(bool(filter(lambda y: y!=1, x))): 0.0030 0.0081 0.2171 0.0689 0.0680 0.7599
all(x): 0.0011 0.0044 0.0230 WA 0.0013 WA
The following test cases were used:
[] # True
[1]*6 # True
[1]*10000 # True
[1]*1000+[2]*1000 # False
[0]*1000+[1]*1000 # False
[random.randint(1, 2) for _ in range(20000)] # False
WA
means that the solution gave a wrong answer; RE
stands for runtime error.
So my verdict is, Winston Ewert‘s x==[1]*len(x)
solution is the fastest in most cases. If you rarely have lists of all ones (the data is random, etc.) or you don’t want to use additional RAM, my solution works better. If the lists are small, the difference is negligible.
Some console examples using all()
‘s cousin any()
:
In [4]: x = [1, 1, 1, 1, 1, 1]
In [5]: not any(i!=1 for i in x)
Out[5]: True
In [6]: x = [1, 1, 1, 1, 1, 0]
In [7]: not any(i!=1 for i in x)
Out[7]: False
In addition to the all()
answer already provided, you can also do it with set()
:
>>> x = [1, 1, 1, 1, 1, 1]
>>> y = set(x)
>>> len(y) == 1 and y.pop() == 1
True
>>> a = [1, 1, 1, 1, 0]
>>> b = set(a)
>>> len(b) == 1 and b.pop() == 1
False
Caveat; (and Redeeming Factor):
- As some have pointed out, this is less readable; however…
- I’ll leave this up since:
- As the results in @WinstonEwert’s answer demonstrate, this solution can perform better than the
all()
solution proposed by @BlaXpirit - I think most members of StackOverflow prefer to learn new things; alternative solutions contribute to that end by prompting discussion, inquiry, and analysis.
- As the results in @WinstonEwert’s answer demonstrate, this solution can perform better than the
This goes through the list and collects any terms that aren’t 1. If those terms exist, then bool returns True and the answer is False.
not(bool(filter(lambda y: y!=1, x)))
@sampson-chen had a good idea that could use some help. Consider up voting his answer and look at this this as an extended comment. (I don’t know how to make code look good in a comment). Here’s my rewrite:
>>> setone = set([1])
>>> x = [1, 1, 1, 1, 1, 1]
>>> set(x) == setone
True
This code does not exactly match the original question because it returns False
for an empty list which could be good or bad but probably doesn’t matter.
Edit
Based on community feedback (thanks @Nabb), here is a second rewrite:
>>> x = [1, 1, 1, 1, 1, 1]
>>> set(x).issubset({1})
This properly handles the case where x is an empty list.
I think this is readable. And the variant part is faster as written (almost twice as fast). In fact, on my Python 2.7 system, it’s always faster for lists up to 20 elements and for lists that are all 1’s. (Up to 3 times faster.)
Update: Vacuous Truth and Reduction of an Empty List
@Peter Olson wrote in a comment:
If the list is empty, then proposition “every element of the list equals one” is vacuously true.
Further discussion in the comments lead up to @sampson-chen writing:
I felt that it ought to be vacuously false; maybe someone in this post will eventually enlighten us on the semantics. – sampson-chen
Let’s see what Python thinks:
>>> all([])
True
Well then how about:
>>> any([])
False
So why is that right? If you haven’t run into this before it might be confusing. There’s a way to think about that may help you understand and remember.
Let’s back up a little bit and start with:
>>> sum(mylist)
Python’s built-in function sum
sums items of an iterable from left to right and returns the total. Thinking more abstractly, sum
reduces an iterable by applying the addition operator.
>>> sum([])
0
The sum of nothing is 0. That’s fairly intuitive. But what about this:
>>> product([])
Okay, it actually returns a name error because product
doesn’t exist as a built-in function. But what should it return? 0? No, the value of an empty product is 1. That’s most mathematically consistent (click the link for a full explanation), because 1 is the identity element for multiplication. (Remember sum([])
returned 0, the identity element for addition.)
Taking this understanding of the special role the identity element plays, and returning to the original problem:
all([])
Is equivalent to reducing the list using the Boolean and
operator. The identity element for and
is True, so the result for the empty list is True
.
any([])
The identity element for or
is False
, the same as the value of this expression.
Yet more possible methods:
x == [1] * len(x)
list(set(x)) == [1]
tuple(set(x)) == (1,)
Some timing results:
all(el==1 for el in x) [1.184262990951538, 1.1856739521026611, 1.1883699893951416]
y = set(x);len(y) == 1 and y.pop() == 1 [0.6140780448913574, 0.6152529716491699, 0.6156158447265625]
set(x) == set([1]) [0.8093318939208984, 0.8106880187988281, 0.809283971786499]
not(bool(filter(lambda y: y!=1, x))) [1.615243911743164, 1.621769905090332, 1.6134231090545654]
not any(i!=1 for i in x) [1.1321749687194824, 1.1325697898864746, 1.132157802581787]
x == [1]*len(x) [0.3790302276611328, 0.3765430450439453, 0.3812289237976074]
list(set(x)) == [1] [0.9047720432281494, 0.9006211757659912, 0.9024860858917236]
tuple(set(x)) == (1,) [0.6586658954620361, 0.6594271659851074, 0.6585478782653809]
And on PyPy because: why not?
all(el==1 for el in x) [0.40866899490356445, 0.5661730766296387, 0.45672082901000977]
y = set(x);len(y) == 1 and y.pop() == 1 [0.6929471492767334, 0.6925959587097168, 0.6805419921875]
set(x) == set([1]) [0.956063985824585, 0.9526000022888184, 0.955935001373291]
not(bool(filter(lambda y: y!=1, x))) [0.21160888671875, 0.1965351104736328, 0.19921493530273438]
not any(i!=1 for i in x) [0.44970107078552246, 0.509315013885498, 0.4380669593811035]
x == [1]*len(x) [0.5422029495239258, 0.5407819747924805, 0.5440030097961426]
list(set(x)) == [1] [1.0170629024505615, 0.9520189762115479, 0.940842866897583]
tuple(set(x)) == (1,) [0.9174900054931641, 0.9112720489501953, 0.9102160930633545]
how about this :
lo = min(L)
hi = max(L)
if (lo != 1) and (hi != 1) and (lo != hi):
print "fail"
Yet another way is:
arr = [1,1,1,1]
len(arr) == sum(arr) #True if arr is all 1's