Matthias Arras
Matthias Arras

Reputation: 740

Most concise way to get complementary slice in numpy

What is the most concise (compact) way to give the complement of a numpy.array slice? Contrary to a previous post I have no speed consideration but ease of use/readability/generality in mind.

As an example, take the array A=np.array([1,2,3,4,5,6]). I am looking for the complement of A[start:stop], e.g., for the complement of A[2:4] which would be "comp of A[2:4]"=array([1,2,3,6]). I am looking for a solution that works regardless of the content type. So A could contain also arrays, str and ideally in principle be of any dimension for which the normal [start:stop] slice operation works too.

Without claiming generality, this is what I currently use:

def comp(A,start,stop):
    if A.ndim == 1:
        out = np.hstack((A[0:start],A[stop:]))
    else:
        out = np.vstack((A[0:start],A[stop:]))
    return out

Upvotes: 3

Views: 1282

Answers (2)

hpaulj
hpaulj

Reputation: 231530

The r_ solution that @Divakar proposes is a concise one for numpy, but it won't generalize to other classes.

In [195]: np.r_[0:2,4:6]                                                                         
Out[195]: array([0, 1, 4, 5])

It generates a list of indices that you want to keep, essentially concatenate of np.arange(0,2) and np.arange(4,6). Indexing with the list is advanced indexing, which makes a copy.

You can't use such a list to index a Python list or string. They can only index elements. To use it on list:

[alist[i] for i in np.r_[0:2,4:6]]

But lists have a delete syntax alist[2:4]=[]

Strings don't have that because they are immutable.

A more universal approach is to concatenate/join two slices

np.concatenate([arr[0:2], arr[4:6]])
alist[0:2] + alist[4:6]
astr[0:2] + astr[4:6]
np.concatenate([arr[:, 0:2], arr[:, 4:6]], axis=1)

Your hstack/vstack code can be rolled into one with

np.concatenate((A[0:start],A[stop:]),axis=0)

since you are joining the slices on the first dimension in both cases.

The complement of a 2d slice:

arr[2:4, 2:4]

can't be a 2d array. Different numbers of elements are left in each row.

Upvotes: 2

Divakar
Divakar

Reputation: 221624

Here's one concise way with np.r_ to generate those indices and then indexing into the input array -

A[np.r_[:start,stop:len(A)]]

Upvotes: 3

Related Questions