cestpasmoi
cestpasmoi

Reputation: 655

Is there any way of getting multiple ranges of values in numpy array at once?

Let's say we have a simple 1D ndarray. That is:

import numpy as np
a = np.array([1,2,3,4,5,6,7,8,9,10])

I want to get the first 3 and the last 2 values, so that the output would be [ 1 2 3 9 10].

I have already solved this by merging and concatenating the merged variables as follows :

b= a[:2]
c= a[-2:]
a=np.concatenate([b,c])

However I would like to know if there is a more direct way to achieve this using slices, such as a[:2 and -2:] for instance. As an alternative I already tried this :

a = a[np.r_[:2, -2:]] 

but it not seems to be working. It returns me only the first 2 values that is [1 2] ..

Thanks in advance!

Upvotes: 2

Views: 1208

Answers (2)

Kevin
Kevin

Reputation: 3348

Slicing a numpy array needs to be continuous AFAIK. The np.r_[-2:] does not work because it does not know how big the array a is. You could do np.r_[:2, len(a)-2:len(a)], but this will still copy the data since you are indexing with another array.

If you want to avoid copying data or doing any concatenation operation you could use np.lib.stride_tricks.as_strided:

ds = a.dtype.itemsize
np.lib.stride_tricks.as_strided(a, shape=(2,2), strides=(ds * 8, ds)).ravel()

Output:

array([ 1,  2,  9, 10])

But since you want the first 3 and last 2 values the stride for accessing the elements will not be equal. This is a bit trickier, but I suppose you could do:

np.lib.stride_tricks.as_strided(a, shape=(2,3), strides=(ds * 8, ds)).ravel()[:-1]

Output:

array([ 1,  2,  3,  9, 10])

Although, this is a potential dangerous operation because the last element is reading outside the allocated memory.

In afterthought, I cannot find out a way do this operation without copying the data somehow. The numpy ravel in the code snippets above is forced to make a copy of the data. If you can live with using the shapes (2,2) or (2,3) it might work in some cases, but you will only have reading permission to a strided view and this should be enforced by setting the keyword writeable=False.

Upvotes: 4

Isotope
Isotope

Reputation: 143

You could try to access the elements with a list of indices.

import numpy as np
a = np.array([1,2,3,4,5,6,7,8,9,10])
b = a[[0,1,2,8,9]] # b should now be array([ 1,  2,  3,  9, 10])

Obviously, if your array is too long, you would not want to type out all the indices. Thus, you could build the inner index list from for loops. Something like that:

index_list = [i for i in range(3)] + [i for i in range(8, 10)]
b = a[index_list] # b should now be array([ 1,  2,  3,  9, 10])

Therefore, as long as you know where your desired elements are, you can access them individually.

Upvotes: 1

Related Questions