How to count non-null elements in an iterable?
I'm looking for a bet开发者_开发技巧ter/more Pythonic solution for the following snippet
count = sum(1 for e in iterable if e)
len(filter(None, iterable))
Using None
as the predicate for filter
just says to use the truthiness of the items. (maybe clearer would be len(filter(bool, iterable))
)
Honestly, I can't think of a better way to do it than what you've got.
Well, I guess people could argue about "better," but I think you're unlikely to find anything shorter, simpler, and clearer.
Most Pythonic is to write a small auxiliary function and put it in your trusty "utilities" module (or submodule of appropriate package, when you have enough;-):
import itertools as it
def count(iterable):
"""Return number of items in iterable."""
return sum(1 for _ in iterable)
def count_conditional(iterable, predicate=None):
"""Return number of items in iterable that satisfy the predicate."""
return count(it.ifilter(predicate, iterable))
Exactly how you choose to implement these utilities is less important (you could choose at any time to recode some of them in Cython, for example, if some profiling on an application using the utilities shows it's useful): the key thing is having them as your own useful library of utility functions, with names and calling patterns you like, to make your all-important application level code clearer, more readable, and more concise that if you stuffed it full of inlined contortions!-)
sum(not not e for e in iterable)
As stated in the comments, the title is somewhat dissonant with the question. If we would insist on the title, i.e. counting non-null elements, the OP's solution could be modified to:
count = sum(1 for e in iterable if e is not None)
This isn't the fastest, but maybe handy for code-golf
sum(map(bool, iterable))
Propably the most Pythonic way is to write code that does not need count function.
Usually fastest is to write the style of functions that you are best with and continue to refine your style.
Write Once Read Often code.
By the way your code does not do what your title says! To count not 0 elements is not simple considering rounding errors in floating numbers, that False is 0..
If you have not floating point values in list, this could do it:
def nonzero(seq):
return (item for item in seq if item!=0)
seq = [None,'', 0, 'a', 3,[0], False]
print seq,'has',len(list(nonzero(seq))),'non-zeroes'
print 'Filter result',len(filter(None, seq))
"""Output:
[None, '', 0, 'a', 3, [0], False] has 5 non-zeroes
Filter result 3
"""
If you're just trying to see whether the iterable is not empty, then this would probably help:
def is_iterable_empty(it):
try:
iter(it).next()
except StopIteration:
return True
else:
return False
The other answers will take O(N) time to complete (and some take O(N) memory; good eye, John!). This function takes O(1) time. If you really need the length, then the other answers will help you more.
Here is a solution with O(n) runtime and O(1) additional memory:
count = reduce(lambda x,y:x+y, imap(lambda v: v>0, iterable))
Hope that helps!
精彩评论