开发者

Python Multidimensional Arrays - most efficient way to count number of non-zero entries

Hi there on a Saturday Fun Night,

I am getting around in python and I am quite enjoying it.

Assume I have a python array:

x = [1, 0, 0, 1, 3]

What is the fastest way to count all non zero elements in the list (ans: 3) ? Also I would like to do it without for loops if possible - the most succint and terse manner possibe, say something conceptually like

[counter += 1 for y in x if y > 0]

Now - my real problem is that I have a multi dimensional array and what I really want to avoid is doing the following:

for p in range(BINS):
    for q in range(BINS):开发者_高级运维
        for r in range(BINS):
            if (mat3D[p][q][r] > 0): some_feature_set_count += 1

From the little python I have seen, my gut feeling is that there is a really clean syntax (and efficient) way how to do this.

Ideas, anyone?


For the single-dimensional case:

sum(1 for i in x if i)

For the multi-dimensional case, you can either nest:

sum(sum(1 for i in row if i) for row in rows)

or do it all within the one construct:

sum(1 for row in rows
      for i in row if i)


If you are using numpy as suggested by the fact that you're using multi-dimensional arrays in Python, the following is similar to @Marcelo's answer, but a tad cleaner:

>>> a = numpy.array([[1,2,3,0],[0,4,2,0]])
>>> sum(1 for i in a.flat if i)
5
>>>


If you go with numpy and your 3D array is a numpy array, this one-liner will do the trick:

numpy.where(your_array_name != 0, 1, 0).sum()

example:

In [23]: import numpy

In [24]: a = numpy.array([ [[0, 1, 2], [0, 0, 7], [9, 2, 0]], [[0, 0, 0], [1, 4, 6], [9, 0, 3]], [[1, 3, 2], [3, 4, 0], [1, 7, 9]] ])

In [25]: numpy.where(a != 0, 1, 0).sum()
Out[25]: 18


While perhaps not concise, this is my choice of how to solve this which works for any dimension:

def sum(li):
  s = 0
  for l in li:
    if isinstance(l, list):
      s += sum(l)
    elif l:
      s += 1
  return s


def zeros(n):
    return len(filter(lambda x:type(x)==int and x!=0,n))+sum(map(zeros,filter(lambda x:type(x)==list,n)))

Can't really say if it is the fastest way but it is recursive and works with N dimensional lists.

zeros([1,2,3,4,0,[1,2,3,0,[1,2,3,0,0,0]]]) => 10


I would have slightly changed Marcelo's answer to the following:

len([x for x in my_list if x != 0])

The sum() above tricked me for a second, as I thought he was getting the total value instead of count until I seen the 1 hovering at the start. I'd rather be explicit with len().


Using chain to reduce array lookups:

from itertools import chain
BINS = [[[2,2,2],[0,0,0],[1,2,0]],
        [[1,0,0],[0,0,2],[1,2,0]],
        [[0,0,0],[1,1,1],[1,3,0]]]
sum(1 for c in chain.from_iterable(chain.from_iterable(BINS)) if c > 0)
14

I haven't done any performance checks on this. But it doesn't use any significant memory. Note that it is using a generator expression, not a list comprehension. Adding the [list comprehension] syntax will create an array to be summed instead of feeding one number at a time to sum.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜