In my code (Python+numpy or Matlab, but issue can apply to any array programming language), I often need to count the number of elements in an array where the elements are true. Usually, I implement this as sum(x>0.5), but this may be considered improper. See Is it correct to add booleans in order to count the number of true values in a vector?. Numpy has count_nonzero, but if there is no special-purpose function, what would be the proper way to write this?

For example, in Matlab, I can either write sum(x>.5) or length(find(x>0.5)). The former is slightly faster but may be considered improper (see above). Are there any other alternatives for counting the number of true values in an array, and what should be my criteria for selecting one?

(In a low-level language, one would write an explicit for-loop, but that is an extremely inefficient way to implement this in a high-level array programming language)

  • 1
    In a non-time-critical code part, I would always prefer readability over a small efficiency gain. – Vlad Feb 18 '13 at 13:26
  • @Vlad Certainly. Speed is not a significant issue in my choice between the alternatives. – gerrit Feb 18 '13 at 13:28
  • Well, my point is that length(find(x>0.5)) is definitely more clear than sum(x>.5). If there is another one even more clear, I would choose that one. One more good idea would be to throw in a small trivial function with an appropriate name, something like count_true. – Vlad Feb 18 '13 at 13:33
  • I originally read sum(x>0.5) as the sum of all the elements greater than 5, rather than the count of all the elements greater than 5. Clearly, a different intent, probably derived from the fact that I'm not a Python expert. – JohnL Feb 18 '13 at 13:47

This seems like a natural use for a fold to me

i.e. something like this in pseudo functional code

let countiftrue bs = fold (fun acc b -> if b then acc + 1 else acc) 0 bs

better yet have it as a higher order function that accepts a predicate to make it even more useful

let countif p xs = fold (fun acc x -> if p x then acc + 1 else acc) 0 xs

It seems like if you want to count the true elements, you probably want to get the true elements in some other context. Also, getting the true elements and then counting them reads nicely, in my opinion.

My python is rusty, but this will give you the general idea:

def take_true(list):
  return [x for x in list if x]

def true_count(list):
  return len(take_true(list))
  • Yes, take_true is I think identical to NumPys find for a NumPy array, so this would be equivalent to len(find(array)). – gerrit Feb 19 '13 at 8:33

In Python you can use generator expressions with many builtin functions. sum(x for x in vec if x > 0.5) and len(x for x in vec if abs(x) > 1.0) are perfectly valuable. They're equivalent to using a list comprehension like sum([x for x in vec if x > 0.5]) but doesn't have the overhead of needing to building a temporary list.

You can extend this idea by looking into map, filter & reduce (as well as the itertools versions that more efficiently handle iterators).

  • 1
    len(x for x in vec if abs(x) > 1.0) results in TypeError: object of type 'generator' has no len(). – gerrit Feb 19 '13 at 21:09
  • sum(1 for x in vec if x>0.5) works, but takes 867 ms for a 1000000-element array, versus 4.54 ms for count_nonzero. In an array programming language, it is important to try to use vectorised functions so that the loop is in C rather than in Python (explaining the factor 200 speed difference). Although speed is not my major design criterion, a factor 200 can start to be relevant in practice. – gerrit Feb 19 '13 at 21:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.