Asked 1 month ago by NovaScout456
How to Determine the Start and End Indices for a Counter Run in a Numpy Array?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by NovaScout456
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I have a numpy array where a counter increments until it resets (represented by zeros), and I need to determine the start and end indices for a given counter run before the reset. For example, consider the array below:
NUMPYvalues = [0, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 0, 0, 1, 2, 3] index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
For instance:
I would like to know how to achieve this using numpy. I have explored several methods (as seen in the provided answers), but I'm looking for a concise numpy-only solution. Any help or suggestions would be appreciated!
Comments 0
•Answers 5
•Views 100
Answer by TychoAI Agent • 1 month ago
Below is one acceptable “numpy‐only” solution. In our example the “groups” are the contiguous regions of non‑zero (increasing) values. One way to do this is to first find the indices where values is nonzero, then “split” that list into chunks where the indices are contiguous; finally, for a given search index we simply find in which chunk (group) it lies and return the first and last index of that group.
For example, consider the following code:
PYTHONimport numpy as np # your array of values values = np.array([0, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 0, 0, 1, 2, 3]) # Find the indices that are part of a counter (i.e. nonzero values) nonzero_idx = np.where(values != 0)[0] # Find the discontinuities in these nonzero indices. # The diff will be >1 when nonzero indices are not consecutive. gaps = np.diff(nonzero_idx) > 1 # Split the nonzero indices into groups at the discontinuities. # np.split splits the array at positions given by np.where(gaps)[0]+1 groups = np.split(nonzero_idx, np.where(gaps)[0] + 1) def get_group_boundaries(search_index): """ Given a search_index, return (start, end) indices of the counter group in which the index lies, or None if not found. """ # Loop over each contiguous group for group in groups: if group[0] <= search_index <= group[-1]: # Return the boundary indices of the group. return group[0], group[-1] return None # Examples: print(get_group_boundaries(3)) # Outputs: (2, 6) print(get_group_boundaries(10)) # Outputs: (8, 13) print(get_group_boundaries(16)) # Outputs: (16, 18)
How does this work?
We first get the indices of all non‑zero values with np.where(values != 0)[0]
.
We then compute the differences between consecutive nonzero indices with np.diff(nonzero_idx)
. Wherever the gap is larger than 1 the counter has been “reset.”
With np.split
we split the array of nonzero indices into groups (each group representing one contiguous counter).
Finally, for a given search index, we check in which group it lies and return that group’s first and last indices.
This is one acceptable numpy-based approach to solve the problem.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by NebularAdventurer426 • 1 month ago
PYTHONimport numpy as np values = np.array([0, 1, 2, 3, 4, 5, 0, 7, 8, 9, 10, 11, 12, 0, 0, 15, 16, 17]) m = values == 0 idx = np.where(m)[0] aa = np.where(m, np.arange(len(values)), -1) print(aa) #[ 0 -1 -1 -1 -1 -1 6 -1 -1 -1 -1 -1 -1 13 14 -1 -1 -1] startIdx = np.maximum.accumulate(aa, -1) +1 print(startIdx) '''[ 1 1 1 1 1 1 7 7 7 7 7 7 7 14 15 15 15 15]''' bb = np.where(m[::-1], np.arange(len(values))[::-1], len(values) ) print(bb) '''[18 18 18 14 13 18 18 18 18 18 18 6 18 18 18 18 18 0]''' endIdx = np.minimum.accumulate(bb)[::-1] -1 print(endIdx) '''[-1 5 5 5 5 5 5 12 12 12 12 12 12 12 13 17 17 17]''' def getRange(idx): if values[idx] == 0 : return None aa = int(startIdx[idx]) bb = int(endIdx[idx]) return (aa,bb) print(getRange(3)) # Output: (1, 5) print(getRange(10)) # Output: (7, 12) print(getRange(16)) # Output: (15, 17)
No comments yet.
Answer by QuasarAstronaut382 • 1 month ago
You can get the start/end coordinates of the non-null stretches with something like:python idx = np.nonzero(values == 0)[0] start = idx+1 end = np.r_[idx[1:]-1, len(values)-1] m = start<end indices = np.c_[start, end][m]
indices
:python array([[ 2, 6], [ 8, 13], [16, 18]])
Then get the position with searchsorted
(assuming you only pass non-zeros indices, else you need an additional check (e.g. is values[position] != 0
) and explanation of what should be the output):python indices[np.searchsorted(indices[:, 1], 2)] # [ 2, 6] indices[np.searchsorted(indices[:, 1], 10)] # [ 8, 13] indices[np.searchsorted(indices[:, 1], 16)] # [16, 18]
And you can get multiple targets at once:
```python
target = [2, 6, 10, 16]
indices[np.searchsorted(indices[:, 1], target)]
array([[ 2, 6],
[ 2, 6],
[ 8, 13],
[16, 18]])
<br><br>And if you have indices of zero-values you could mask them in the output:<br><br>
python
target = [1, 2, 6, 7, 10, 16]
out = np.ma.masked_array(indices[np.searchsorted(indices[:, 1], target)],
np.broadcast_to(values[target, None]==0, (len(target), 2))
)
[[-- --]
[ 2 6]
[ 2 6]
[-- --]
[ 8 13]
[16 18]]
<br><br>Used input:<br><br>
python
values = np.array([0, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 0, 0, 1, 2, 3])
No comments yet.
Answer by NebularObserver332 • 1 month ago
For example, if you care about index==10
, you can try
PYTHONgrp = np.cumsum(np.append(1,np.diff(values)<0)) np.argwhere(grp ==grp[index==10])[1:].T
which gives
PYTHONarray([[ 8, 9, 10, 11, 12, 13]])
PYTHONvalues = np.array([0, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 0, 0, 1, 2, 3]) index = np.arange(values.size)
No comments yet.
Answer by PlanetaryHunter849 • 1 month ago
PYTHONimport numpy as np arr = np.array([0, 0, 1, 2, 3, 4,5, 0, 1, 2, 3, 4, 5, 6, 0, 0,1, 2, 3]) resets = np.where(arr == 0)[0] # Create an array of boundaries boundaries = np.concatenate(([ -1 ], resets, [ len(arr) ])) def get_run_bounds(arr, boundaries, i): if arr[i] == 0: return None pos= np.searchsorted(boundaries, i, side='right') start = boundaries[pos- 1] + 1 end = boundaries[pos] - 1 return (start, end) print("Index 3→",get_run_bounds(arr, boundaries, 3)) # waiting for(2, 6) print("Index 10 →", get_run_bounds(arr, boundaries, 10)) # (8, 13) print("Index 16 →", get_run_bounds(arr, boundaries, 16))# (16, 18)
No comments yet.
No comments yet.