不确定之前是否曾被问过,但我找不到明显的答案。我正在尝试计算列表中等于某个值的元素数。问题是这些元素不是内置类型。所以,如果我有
class A:
def __init__(self, a, b):
self.a = a
self.b = b
stuff = []
for i in range(1,10):
stuff.append(A(i/2, i%2))
现在我想要一个列表元素的计数,其字段b = 1.我提出了两个解决方案:
print [e.b for e in stuff].count(1)
和
print len([e for e in stuff if e.b == 1])
哪种方法最好?还有更好的选择吗?似乎count()方法不接受键(至少在Python 2.5.1版中。
非常感谢!
答案 0 :(得分:41)
sum(x.b == 1 for x in L)
布尔(由x.b == 1
等比较产生)也是int
,0
的值为False
,1
的值为True
{1}},所以像求和这样的算法就可以了。
这是最简单的代码,但也许不是最快的(只有timeit
可以告诉你肯定;-)。考虑(简化的情况,以适应命令行,但等效):
$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'len([x for x in L if x==1])'
10000 loops, best of 3: 56.6 usec per loop
$ py26 -mtimeit -s'L=[1,2,1,3,1]*100' 'sum(x==1 for x in L)'
10000 loops, best of 3: 87.7 usec per loop
因此,对于这种情况,生成额外临时列表并检查其长度的“内存浪费”方法实际上比我更喜欢的更简单,更短,更节省内存的方法更快。列表值的其他组合,Python实现,在这种加速中“投入”的内存可用性等,当然会影响确切的性能。
答案 1 :(得分:14)
print sum(1 for e in L if e.b == 1)
答案 2 :(得分:2)
我更喜欢第二个,因为它只会在列表上循环一次。
如果您使用count()
,您将循环遍历列表一次以获取b
值,然后再次循环以查看其中有多少等于1.
可以使用reduce()
:
reduce(lambda x,y: x + (1 if y.b == 1 else 0),list,0)
The documentation告诉我们reduce()
将:
将两个参数的函数累加到iterable的项目中,从左到右,以便将iterable减少为单个值。
因此,我们定义lambda
,只有在列表项的b
属性为1时,才会添加一个累计值。
答案 3 :(得分:0)
要隐藏reduce
详细信息,您可以定义count
功能:
def count(condition, stuff):
return reduce(lambda s, x: \
s + (1 if condition(x) else 0), stuff, 0)
然后你可以通过提供计数条件来使用它:
n = count(lambda i: i.b, stuff)
答案 4 :(得分:-1)
给定输入
name = ['ball', 'jeans', 'ball', 'ball', 'ball', 'jeans']
price = [1, 4, 1, 1, 1, 4]
weight = [2, 2, 2, 3, 2, 2]
首先创建一个 defaultdict
来记录事件
from collections import defaultdict
occurrences = defaultdict(int)
增加计数
for n, p, w in zip(name, price, weight):
occurrences[(n, p, w)] += 1
最后统计出现多次的那些(True
会产生1)
print(sum(cnt > 1 for cnt in occurrences.values())