2

I have the foll. python numpy array, arr:

([1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 3L, 3L, 3L, 2L, 2L, 2L,
       2L, 2L, 2L, 1L, 1L, 1L, 1L])

I can find the first occurrence of 1 like this:

np.where(arr.squeeze() == 1)[0]

How do I find the position of the last 1 before either a 0 or 3.

2 Answers 2

2

Here's one approach using np.where and np.in1d -

# Get the indices of places with 0s or 3s and this 
# decides the last index where we need to look for 1s later on
last_idx = np.where(np.in1d(arr,[0,3]))[0][-1]

# Get all indices of 1s within the range of last_idx and choose the last one
out = np.where(arr[:last_idx]==1)[0][-1]

Please note that for cases where no indices are found, using something like [0][-1] would complain about having no elements, so error-checking codes are needed to be wrapped around those lines.

Sample run -

In [118]: arr
Out[118]: array([1, 1, 3, 0, 3, 2, 0, 1, 2, 1, 0, 2, 2, 3, 2])

In [119]: last_idx = np.where(np.in1d(arr,[0,3]))[0][-1]

In [120]: np.where(arr[:last_idx]==1)[0][-1]
Out[120]: 9
Sign up to request clarification or add additional context in comments.

Comments

1

You can use a rolling window and search that for the values you want:

import numpy as np
arr = np.array([1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 3L, 3L, 3L, 2L, 2L, 2L,
       2L, 2L, 2L, 1L, 1L, 1L, 1L])

def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

match_1_0 = np.all(rolling_window(arr, 2) == [1, 0], axis=1)
match_1_3 = np.all(rolling_window(arr, 2) == [1, 3], axis=1)
all_matches = np.logical_or(match_1_0, match_1_3)
print(np.flatnonzero(all_matches)[-1])

Depending on your arrays, this might be good enough performance-wise. With that said, a less flexible (but simpler) solution might perform better even if it is a loop over indices that you usually want to avoid with numpy...:

for ix in xrange(len(arr) - 2, -1, -1):  # range in python3.x
    if arr[ix] == 1 and (arr[ix + 1] == 0 or arr[ix + 1] == 3):
        return ix

You might even be able to do something like which is probably a bit more flexible than the hard-coded solution above and (I would guess) still probably would out-perform the rolling window solution:

def rfind(haystack, needle):
    len_needle = len(needle)
    for ix in xrange(len(haystack) - len_needle, -1, -1):  # range in python3.x
        if (haystack[ix:ix + len_needle] == needle).all():
            return ix

Here, you'd do something like:

max(rfind(arr, np.array([1, 0])), rfind(arr, np.array([1, 3])))

And of course, with all of these answers, I haven't actually handled the case where the thing you are searching for isn't present since you didn't specify what you would want for that case...

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.