2013-10-07 59 views
6

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

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

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

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

有没有更好的办法?

+3

“更好”是主观这里还取决于一点上,其中3例您希望大部分经常打,它甚至可能取决于列表的长度等。 – mgilson

+0

@mgilson,好点。我不知道哪种情况会比其他情况更频繁地出现,而属性'a'是根据用户的输入设置的。我知道列表的长度很短,即<= 1000个项目。 – ChrisG

回答

18

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

>>> 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)被解释为具有真或假值。

+0

+1如果我的ISP没有决定死的话,我会在几分钟之前发布答案。 :-)(除了单线,这是代码高尔夫球)。 –

+0

不,它不是代码高尔夫,你能看到那个可怕的长参数名吗? –

2

你也可以使用集合。

s = set([i.a for i in your_list]) 
if len(s) == 1: 
    b = s.pop() 
else: 
    b = 2 
+1

设置的对象不支持索引。使用'next(iter(s))'。另外,为什么'i.a'? – Noctua

+0

i.a只是简单地将一个值从对象列表中拉出来,如问题中所示: “我有一个项目列表,每个项目都有一个属性a,它的值是二进制的。” – bcollins

+0

是的,感谢评论Noctua。集不支持索引。我还看到一些内联条件的奇怪行为,并将其删除。我想我喜欢任何/所有回答最好的 – bcollins

26

一次通过名单,并没有多余的数据结构构造:

def zot(bs): 
    n, s = len(bs), sum(bs) 
    return 1 if n == s else 2 if s else 0 
+0

很好。 zot是什么意思?零一,二? – bcollins

+1

这提请注意角落案例'bs == []'。有趣的是,我们的解决方案以相同的方式处理它('zot'和'category'都返回'1'),但我不确定这是否是正确的响应。 'all([])'返回'True',而any([])'返回False,所以如果我以不同的方式组织我的if语句,'category([])'会返回'0'。 – senderle

+0

我认为问题陈述是矛盾的:那么对于一个空输入来说,所有的都是0并且全部都是1.所以我们返回两个正确答案的总和;-) –

1

您可以定义两个布尔瓦尔hasZerohasOne,并将其设置为True如果对应值满足,而迭代列表。然后b = 2如果hasZero and hasOne,b = 1如果只有hasOneb = 0如果只有hasZero

另一种方法:您可以将所有的a值加在列表中。如果sumA == len(list)然后b = 1,如果sumA == 0然后b = 0并且如果0 < sumA < len(list)然后b = 2

15

有人提到代码高尔夫球,所以不能抵抗上@ senderle的一个变化:

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

短解释:这将使用布尔值作为其整数当量至索引所需的响应的列表。如果all为真,那么any也必须为真,因此它们的总和为2any本身给出1,没有匹配给出0。这些指数从列表中返回相应的值。

如果原来的规定都可以修改为使用1any2all刚刚返回any + all

+0

+1,真正pythonic的方式:) – kasitan

1

的短路解决方案的整数它会更简单。可能是最有效的方法,你可以在Python中完成它。

编辑:包括anyall根据意见中的建议。

编辑2:它现在是一个班轮。

b = 1 if all(A) else 2 if any(A) else 0 
+1

内置的任何()和全部()函数短路,并可能比任何明确的循环项目。 – martineau

+0

@martineau显式循环是在C中实现的,与'any'和'all'完全相同。我不明白为什么迭代会比你的方法慢。 – Shashank

+0

循环未在C中以相同的方式实现。 – martineau

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) 
3

使用词典:

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

这也只需要通过列表中的一个通行证。

+0

确实如此,它是一次传递,但它访问列表中的每个对象并在此过程中构建一个'frozenset'。 – martineau

0

您可以使用列表iter ators:

>>> 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 
2
def zot(bs): 
    return len(set(bs)) if sum(bs) else 0 
相关问题