A trivial change to my answer at Finding the consecutive zeros in a numpy array gives the function find_runs
:
def find_runs(value, a):
# Create an array that is 1 where a is `value`, and pad each end with an extra 0.
isvalue = np.concatenate(([0], np.equal(a, value).view(np.int8), [0]))
absdiff = np.abs(np.diff(isvalue))
# Runs start and end where absdiff is 1.
ranges = np.where(absdiff == 1)[0].reshape(-1, 2)
return ranges
For example,
In [43]: x
Out[43]: array([1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1])
In [44]: find_runs(1, x)
Out[44]:
array([[ 0, 4],
[ 9, 12],
[14, 16],
[20, 22]])
In [45]: [range(*run) for run in find_runs(1, x)]
Out[45]: [[0, 1, 2, 3], [9, 10, 11], [14, 15], [20, 21]]
If the value 1
in your example was not representative, and you really want runs of any non-zero values (as suggested by the text of the question), you can change np.equal(a, value)
to (a != 0)
and change the arguments and comments appropriately. E.g.
def find_nonzero_runs(a):
# Create an array that is 1 where a is nonzero, and pad each end with an extra 0.
isnonzero = np.concatenate(([0], (np.asarray(a) != 0).view(np.int8), [0]))
absdiff = np.abs(np.diff(isnonzero))
# Runs start and end where absdiff is 1.
ranges = np.where(absdiff == 1)[0].reshape(-1, 2)
return ranges
For example,
In [63]: y
Out[63]:
array([-1, 2, 99, 99, 0, 0, 0, 0, 0, 12, 13, 14, 0, 0, 1, 1, 0,
0, 0, 0, 42, 42])
In [64]: find_nonzero_runs(y)
Out[64]:
array([[ 0, 4],
[ 9, 12],
[14, 16],
[20, 22]])