16

Suppose I have this NumPy array:

a = np.array([0, 3, 5, 5, 0, 10, 14, 15, 56, 0, 12, 23, 45, 23, 12, 45, 
              0, 1, 0, 2, 3, 4, 0, 0 ,0])

I would like to print all the numbers between 0s and automatically add them to a new np.array (see below):

a1=[3, 5, 5]
a2=[10, 14, 15, 56]
a3=[12, 23, 45, 23, 12, 45]
a4=[1]
a5=[2, 3, 4]

Is there a built-in function to do this?

0

6 Answers 6

13

Here's a vectorized approach using np.where and np.split -

idx = np.where(a!=0)[0]
aout = np.split(a[idx],np.where(np.diff(idx)!=1)[0]+1)

Sample run -

In [23]: a
Out[23]: 
array([ 0,  3,  5,  5,  0, 10, 14, 15, 56,  0,  0,  0, 12, 23, 45, 23, 12,
       45,  0,  1,  0,  2,  3,  4,  0,  0,  0])

In [24]: idx = np.where(a!=0)[0]

In [25]: np.split(a[idx],np.where(np.diff(idx)!=1)[0]+1)
Out[25]: 
[array([3, 5, 5]),
 array([10, 14, 15, 56]),
 array([12, 23, 45, 23, 12, 45]),
 array([1]),
 array([2, 3, 4])]
Sign up to request clarification or add additional context in comments.

Comments

7

You can use groupby() function from itertools, and specify the key as the boolean condition of zero or nonzero. In such a way, all consecutive zeros and nonzeros will be grouped together. Use if filter to pick up groups of nonzeros and use list to convert the non zero groupers to lists.

from itertools import groupby
[list(g) for k, g in groupby(a, lambda x: x != 0) if k]

# [[3, 5], [10, 14, 15, 56], [12, 23, 45, 23, 12, 45], [1], [2, 3, 4]]

Comments

3

You can get the indices of zeros with np.where:

zeros = np.where(a == 0)[0]

And iterate over every pair to slice the array:

[a[i+1:j] for i, j in zip(zeros, zeros[1:]) if len(a[i+1:j])>0]

Out[46]: 
[array([3, 5]),
 array([10, 14, 15, 56]),
 array([12, 23, 45, 23, 12, 45]),
 array([1]),
 array([2, 3, 4])]

6 Comments

This solution does not work if the array starts with a non-zero integer, e.g. a = np.array([1, 0, 3, 5, 0, 0, 10, 0])
@Alexander It outputs [3, 5] and [10]. Isn't this correct?
With the sample I gave above, it should be [[1], [3, 5], [10]]
@Alexander Shouldn't 1 have 0 on the left side of it to be considered between zeros?
Fair enough. Your answer is appears to solve what the OP has requested (although the question could be interpreted as splitting the array on zeros).
|
3

NumPy's split() and where() in a list compehension:

[x[x!=0] for x in np.split(a, np.where(a==0)[0]) if len(x[x!=0])]

[array([3, 5, 5]),
 array([10, 14, 15, 56]),
 array([12, 23, 45, 23, 12, 45]),
 array([1]),
 array([2, 3, 4])]

Comments

0

No need for numpy, this lambda function works on a list, but we can convert your numpy array to and from a list on the way in and out:

cut = lambda x: [j for j in [cut(x[:x.index(0)])]+cut(x[x.index(0)+1:]) if j] if x.count(0) else x

numpy.array(cut(list(a)))

# array([[3, 5, 5], [10, 14, 15, 56], [12, 23, 45, 23, 12, 45], [1], [2, 3, 4]], dtype=object)

Comments

0

This is probably the worst way to do this, but you could also convert your array into a string and then split that string a couple times:

long_string = "_".join(a.astype(str))

while long_string.startswith("0_"):
    long_string = long_string.removeprefix("0_")
while long_string.endswith("_0"):
    long_string = long_string.removesuffix("_0")

result = [list(map(int, i.split("_"))) for i in long_string.split("_0_")]

# result: [[3, 5, 5], [10, 14, 15, 56], [12, 23, 45, 23, 12, 45], [1], [2, 3, 4]]

You would need Python 3.9 for .removeprefix() and .removesuffix().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.