Мы можем сделать что-то подобное для любого универсального массива -
def islandinfo(y, trigger_val, stopind_inclusive=True):
# Setup "sentients" on either sides to make sure we have setup
# "ramps" to catch the start and stop for the edge islands
# (left-most and right-most islands) respectively
y_ext = np.r_[False,y==trigger_val, False]
# Get indices of shifts, which represent the start and stop indices
idx = np.flatnonzero(y_ext[:-1] != y_ext[1:])
# Lengths of islands if needed
lens = idx[1::2] - idx[:-1:2]
# Using a stepsize of 2 would get us start and stop indices for each island
return zip(idx[:-1:2], idx[1::2]-int(stopind_inclusive)), lens
Пробный прогон -
In [320]: y
Out[320]: array([1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1])
In [321]: islandinfo(y, trigger_val=1)[0]
Out[321]: [(0, 2), (8, 9), (16, 19)]
In [322]: islandinfo(y, trigger_val=0)[0]
Out[322]: [(3, 7), (10, 15)]
В качестве альтернативы, мы можем использовать diff
, чтобы получить срезы сравнения, а затем просто изменить форму столбцами 2
, чтобы заменить пошаговое нарезание, чтобы получить однострочность -
In [300]: np.flatnonzero(np.diff(np.r_[0,y,0])!=0).reshape(-1,2) - [0,1]
Out[300]:
array([[ 0, 2],
[ 8, 9],
[16, 19]])