40

我正在寻找更好的方法,可能是使用列表推导?

>>> 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
>>> 
4

8 回答 8

78
>>> x = [1, 1, 1, 1, 1, 1]
>>> all(el==1 for el in x)
True

这将函数all生成器表达式一起使用。


如果列表中总是只有零和一个(或者如果您只想检查列表是否没有任何零),那么只需使用all没有任何额外的技巧:

>>> x = [1, 0, 1, 1, 1, 0]
>>> all(x)
False

一些解决方案的基准:
数字表示运行一次解决方案所需的时间(以毫秒为单位) (平均 1000timeit次运行)

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  

使用了以下测试用例:

[] # 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表示解决方案给出了错误的答案RE代表运行时错误


所以我的判断是,Winston Ewertx==[1]*len(x) 解决方案在大多数情况下是最快的。如果您很少有所有列表(数据是随机的等),或者您不想使用额外的 RAM,我的解决方案效果更好。如果列表很小,则差异可以忽略不计。

于 2012-11-28T19:39:18.520 回答
42

还有更多可能的方法:

x == [1] * len(x)

list(set(x)) == [1]

tuple(set(x)) == (1,)

一些计时结果:

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]

在 PyPy 上,因为:为什么不呢?

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]
于 2012-11-28T22:20:22.423 回答
16

除了all()已经提供的答案之外,您还可以使用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

警告; (和兑换因素)

  • 正如一些人指出的那样,这不太可读。然而...
  • 我会留下这个,因为:
    • 正如@WinstonEwert 答案中的结果所表明的那样,该解决方案的性能优于all()@BlaXpirit 提出的解决方案
    • 我认为 StackOverflow 的大多数成员都喜欢学习新事物;替代解决方案通过促进讨论、调查和分析来实现这一目标。
于 2012-11-28T19:45:50.430 回答
10

@sampson-chen 有一个好主意,可以使用一些帮助。考虑投票他的答案并将其视为扩展评论。(我不知道如何使代码在评论中看起来不错)。这是我的重写:

>>> setone = set([1])
>>> x = [1, 1, 1, 1, 1, 1]
>>> set(x) == setone
True

此代码与原始问题不完全False匹配,因为它返回一个空列表,该列表可能好坏,但可能无关紧要。

编辑

根据社区反馈(感谢@Nabb),这是第二次重写:

>>> x = [1, 1, 1, 1, 1, 1]
>>> set(x).issubset({1})

这可以正确处理 x 为空列表的情况。

我认为这是可读的。并且变体部分比写的要快(几乎快两倍)。事实上,在我的 Python 2.7 系统上,最多 20 个元素的列表和全为 1 的列表总是更快。(最多快 3 倍。)

更新:空列表的空洞真相和减少

@Peter Olson 在评论中写道:

如果列表为空,则命题“列表的每个元素都等于一个”是空虚的

评论中的进一步讨论导致@sampson-chen 写作:

我觉得它应该是空洞的错误;也许这篇文章中的某个人最终会在语义上启发我们。– 桑普森陈

让我们看看 Python 是怎么想的:

>>> all([])
True

那么怎么样:

>>> any([])
False

那为什么是对的呢?如果您之前没有遇到过这种情况,可能会感到困惑。有一种思考方式可以帮助你理解和记忆。

让我们稍微备份一下,然后开始:

>>> sum(mylist)

Python 的内置函数sum从左到右对可迭代的项求和并返回总数。更抽象地思考,sum通过应用加法运算符来减少迭代。

>>> sum([])
0

什么都没有的总和是 0。这很直观。但是这个呢:

>>> product([])

好的,它实际上返回了一个名称错误,因为product它不作为内置函数存在。但它应该返回什么?0? 不,空乘积的值是 1。这在数学上是最一致的(单击链接查看完整说明),因为 1 是乘法的单位元。(记住sum([])返回 0,加法的标识元素。)

以此理解恒等元素所起的特殊作用,回到原来的问题:

all([])

相当于使用布尔and运算符减少列表。的标识元素为andTrue,因此空列表的结果为True

any([])

的标识元素orFalse,与此表达式的值相同。

于 2012-11-28T20:46:19.627 回答
2

这将遍历列表并收集任何不是 1 的术语。如果这些术语存在,则 bool 返回 True,答案为 False。

not(bool(filter(lambda y: y!=1, x)))
于 2012-11-28T20:10:10.163 回答
1

一些使用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
于 2012-11-28T19:39:24.147 回答
1

这个怎么样 :

lo = min(L)
hi = max(L)
if (lo != 1) and (hi != 1) and (lo != hi):
   print "fail"
于 2012-11-29T09:31:06.610 回答
1

还有一种方法是:

arr = [1,1,1,1]
len(arr) == sum(arr) #True if arr is all 1's
于 2012-12-07T02:47:37.200 回答