6

这可能是一个微不足道的问题,但我想更多地了解其他更聪明、更有效的解决方法。

我有一个项目列表,每个项目都有一个a值为二进制的属性。

  • 如果列表中的每个项目都有a == 0,那么我设置一个单独的变量b = 0
  • 如果列表中的每个项目都有a == 1,那么我设置b = 1.
  • 如果列表中有a == 0和的混合a == 1,那么我设置 b = 2.

我可以使用集合来跟踪a值的类型,这样如果在遍历列表后集合中有两个项目,那么我可以设置b = 2,而如果集合中只有一个项目,我只检索项目(0 或 1)并使用它来设置b.

有更好的办法吗?

4

10 回答 10

26

遍历列表,没有构建额外的数据结构:

def zot(bs):
    n, s = len(bs), sum(bs)
    return 1 if n == s else 2 if s else 0
于 2013-10-07T16:01:28.737 回答
18

我建议使用anyand all。我会说这样做的好处是可读性而不是聪明或效率。例如:

>>> vals0 = [0, 0, 0, 0, 0]
>>> vals1 = [1, 1, 1, 1, 1]
>>> vals2 = [0, 1, 0, 1, 0]
>>> def category(vals):
...     if all(vals):
...         return 1
...     elif any(vals):
...         return 2
...     else:
...         return 0
... 
>>> category(vals0)
0
>>> category(vals1)
1
>>> category(vals2)
2

如果您愿意,可以缩短一点:

>>> def category(vals):
...     return 1 if all(vals) else 2 if any(vals) else 0
... 

这适用于任何可以被__nonzero__(或__bool__在 Python 3 中)解释为具有真或假值的东西。

于 2013-10-07T15:47:39.933 回答
15

有人提到了代码高尔夫,所以无法抗拒@senderle 的变化:

[0,2,1][all(vals) + any(vals)]

简短说明:这使用布尔值作为它们的整数等价物来索引所需响应的列表。如果all为真,那么any也一定为真,所以它们的和为2any本身给出1,没有匹配给出0。这些索引从列表中返回相应的值。

如果可以修改原始要求以使用1forany2for all,则仅返回整数会更简单any + all

于 2013-10-07T16:35:53.977 回答
3

使用字典:

zonk_values = {frozenset([0]): 0, frozenset([1]): 1, frozenset([0, 1]): 2}
def zonk(a):
    return zonk_values[frozenset(a)]

这也只需要通过列表一次。

于 2013-10-07T17:14:26.533 回答
2
def zot(bs):
    return len(set(bs)) if sum(bs) else 0
于 2013-10-20T05:32:49.240 回答
2

你也可以使用集合。

s = set([i.a for i in your_list])
if len(s) == 1:
    b = s.pop()
else:
    b = 2
于 2013-10-07T15:55:15.903 回答
1

您可以定义两个布尔变量hasZerohasOne并将它们设置为True在迭代列表时是否满足相应的值。那么b = 2如果hasZero and hasOneb = 1如果只有hasOneb = 0如果只有hasZero

另一种方式:您可以a对列表中的所有值求和。如果sumA == len(list)那么b = 1,如果sumA == 0那么b = 0,如果0 < sumA < len(list)那么b = 2

于 2013-10-07T16:04:00.830 回答
1

短路解决方案。可能是您在 Python 中可以做到的最有效的方法。

编辑:包括anyall根据评论中的建议。

EDIT2:它现在是单线的。

b = 1 if all(A) else 2 if any(A) else 0
于 2013-10-07T16:40:23.937 回答
0

您可以使用列表iter生成器:

>>> L = [0, 0, 0, 0, 0]
>>> L1 = [1, 1, 1, 1, 1]
>>> L2 = [0, 1, 0, 1, 0]
>>> def fn(i):
...     i = iter(i)
...     if all(i): return 1
...     return 2 if any(i) else 0
... 
>>> fn(L)
0
>>> fn(L1)
1
>>> fn(L2)
2
于 2013-10-20T05:15:35.550 回答
0

这与 senderle 的建议类似,但编写是为了访问对象的a属性。

from random import randint

class Item(object):
    def __init__(self, a):
        self.a = a

all_zeros = [Item(0) for _ in xrange(10)]
all_ones = [Item(1) for _ in xrange(10)]
mixture = [Item(randint(0, 1)) for _ in xrange(10)]

def check(items):
    if all(item.a for item in items):
        return 1
    if any(item.a for item in items):
        return 2
    else:
        return 0

print 'check(all_zeros):', check(all_zeros)
print 'check(all_ones):', check(all_ones)
print 'check(mixture):', check(mixture)
于 2013-10-07T17:03:19.380 回答