Conditional counting in Python
sum(x.b == 1 for x in L)
A boolean (as resulting from comparisons such as x.b == 1
) is also an int
, with a value of 0
for False
, 1
for True
, so arithmetic such as summation works just fine.
This is the simplest code, but perhaps not the speediest (only timeit
can tell you for sure;-). Consider (simplified case to fit well on command lines, but equivalent):
$ 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
So, for this case, the "memory wasteful" approach of generating an extra temporary list and checking its length is actually solidly faster than the simpler, shorter, memory-thrifty one I tend to prefer. Other mixes of list values, Python implementations, availability of memory to "invest" in this speedup, etc, can affect the exact performance, of course.
I would prefer the second one as it's only looping over the list once.
If you use count()
you're looping over the list once to get the b
values, and then looping over it again to see how many of them equal 1.
A neat way may to use reduce()
:
reduce(lambda x,y: x + (1 if y.b == 1 else 0),list,0)
The documentation tells us that reduce()
will:
Apply function of two arguments cumulatively to the items of iterable, from left to right, so as to reduce the iterable to a single value.
So we define a lambda
that adds one the accumulated value only if the list item's b
attribute is 1.