Markus Dutschke
Markus Dutschke

Reputation: 10606

Slicing of ndarrays over array boundaries

Question:

given a ndarray:

In [2]: a
Out[2]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

I look for a routine giving me:

array([7, 8, 9, 0, 1])

Ex.: Starting at index 8, crossing the array boundarie and stopping at index 2 (included) If I use slicing, I (of course) get:

In [3]: a[-3:2]
Out[3]: array([], dtype=int64)

A possible answer:

Is to use the roll function.

In [5]: np.roll(a,3)[:5]
Out[5]: array([7, 8, 9, 0, 1])

What I look for:

What I do not like concerning this one, is that it is not as straightforward as slicing. So I look for something like:

In [6]: a.xxx[-3:2]

A syntax similar to this one exists for example in pandas.DataFrame.iloc. Thank you very much in advance!

Note: iloc, does not do what I want. I just reffered to the syntax (which i like). Thanks for the comment, cᴏʟᴅsᴘᴇᴇᴅ

Upvotes: 3

Views: 134

Answers (3)

Markus Dutschke
Markus Dutschke

Reputation: 10606

use np.arange()

3 years after asking this questing, this just popped into my head ...

>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a[np.arange(-3, 2)]
array([7, 8, 9, 0, 1])

Upvotes: 0

Banana
Banana

Reputation: 1187

Not nearly as beautiful as coldspeeds solution or rolling, but

def over_edge_slicing(arr, start, end):
    return np.append(arr[start:], arr[:end])

a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(over_edge_slicing(a, -3, 2))

would be another way to write this. However, you lose generality (you cant use this to slice from index 2-4 for example).

Upvotes: 1

cs95
cs95

Reputation: 402263

There isn't any slicing mechanism in python/numpy which automatically wraps around lists/arrays (as circular containers) as you seem to be looking for, so really the only way to do this is using functions. What you're doing with roll is nice and compact, even if it isn't as idiomatic as you like. Below, I've outlined a couple of (slightly more) idiomatic/pythonic solutions, which do the same thing.

Option 1
np.take based on hpaulj's comment:

np.take(a, range(len(a) - 3, len(a) + 2), mode='wrap')
array([7, 8, 9, 0, 1])

Option 2
isliceing a cycle object:

from itertools import islice, cycle

list(islice(cycle(a), len(a) - 3, len(a) + 2))
[7, 8, 9, 0, 1] 

Upvotes: 3

Related Questions