在可迭代的事物中计算匹配元素的大多数pythonic方法
问题内容:
我想输入一些简单的统计数据,例如,所有数字的整数可以除以2,所有数字的整数可以除以3。
我的第一个选择是,虽然只循环遍历列表一次并避免了列表扩展(并牢记分解循环的重构),但看起来却很肿:
(替代项1)
r = xrange(1, 10)
twos = 0
threes = 0
for v in r:
if v % 2 == 0:
twos+=1
if v % 3 == 0:
threes+=1
print twos
print threes
这看起来不错,但是有将表达式扩展到列表的缺点:
(替代2)
r = xrange(1, 10)
print len([1 for v in r if v % 2 == 0])
print len([1 for v in r if v % 3 == 0])
我真正想要的是像这样的函数:
(替代项3)
def count(iterable):
n = 0
for i in iterable:
n += 1
return n
r = xrange(1, 10)
print count(1 for v in r if v % 2 == 0)
print count(1 for v in r if v % 3 == 0)
但这看起来很像没有功能就可以完成的事情。最终的变体是这样的:
(替代项4)
r = xrange(1, 10)
print sum(1 for v in r if v % 2 == 0)
print sum(1 for v in r if v % 3 == 0)
尽管体积最小(在我的书中可能是最优雅的),但它并不能很好地表达意图。
因此,我对您的问题是:
您最喜欢哪种方法来收集这些类型的统计信息?如果您有更好的东西,请随时提供自己的选择。
为了清除以下混淆:
- 实际上,我的过滤谓词比这个简单的测试还要复杂。
- 我要遍历的对象比数字更大,更复杂
- 我的过滤器功能更加不同,难以将其参数化为一个谓词
问题答案:
不得不反复遍历列表并不是很好的恕我直言。
我可能会创建一个允许执行以下操作的函数:
twos, threes = countmatching(xrange(1,10),
lambda a: a % 2 == 0,
lambda a: a % 3 == 0)
起点将是这样的:
def countmatching(iterable, *predicates):
v = [0] * len(predicates)
for e in iterable:
for i,p in enumerate(predicates):
if p(e):
v[i] += 1
return tuple(v)
顺便说一句,“ itertools食谱”有一个类似alt4的食谱。
def quantify(seq, pred=None):
"Count how many times the predicate is true in the sequence"
return sum(imap(pred, seq))