Jian
Jian

Reputation: 209

adding multiple slices in python

I want to get the slice of x[start1:stop1:step1 ] and x[start2:stop2:step2] in a single array.

Is there any syntax in Python like this:

x[start1:stop1:step1  +  start2:stop2:step2]

In Matlab it is simply:

x(start1:step1:stop1  start2:step2:stop2)


update:

I see many answers suggest concatenation.

My intial goal is to do slice for higher dimension array, for example in 2D:

x[start1:stop1 +  start2:stop2,  start3:stop3  +  start4:stop4]

Concatenation is okay. But it seems too complicated in high dimension.

Is there a way as simple as Matlab?

x(start1:stop1  start2:stop2, start3:stop3  start4:stop4 )

can we concatenate the array index, instead of the array itself?

see my solution below

the Tartan

Upvotes: 2

Views: 6711

Answers (6)

Stuart
Stuart

Reputation: 9858

Your answer indicates you are using numpy, so you can use r_ for this instead of constructing ranges.

test=np.random.random((20,20))
test[np.r_[1:8:2, 1:9:3], :][:, np.r_[1:9:3, 2:10:3]]

Indexing multidimensional arrays using sequences has been designed to work a bit differently from indexing using slices. e.g. test[[0, 1, 2], [3, 4, 5]] will return an array containing test[0, 3], test[1, 4], test[2, 5]. That's why test[D1, D2] in your answer doesn't work.

If you want a slightly more convenient syntax you could make a class extending ndarray with an altered method for handling indices:

class MultiArray(np.ndarray):
    """ An array that can be indexed by multiple lists or arrays of indices
    in the same way as by slices e.g.
    m = MultiArray([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
    m[[1, 2], [0, 3, 2]]  # returns [[5, 8, 7], [9, 12, 11]]

    Returns a standard array.
    """
    def __new__(cls, input_array):
        return np.asarray(input_array).view(cls)

    def __getitem__(self, key):
        r = np.array(self)
        if type(key) is tuple:
            for dimension, index in enumerate(key):
                indices = [slice(None)] * len(key)
                indices[dimension] = index
                r = r[tuple(indices)]
            return r
        else:
            return r[key]     

print(MultiArray(test)[np.r_[1:8:2, 1:9:3], np.r_[1:9:3, 2:10:3]])

Upvotes: 2

Jian
Jian

Reputation: 209

Here is my solution:

D1=list(range(start1,stop1,step1))+list(range(start2,stop2,step2))
D2=list(range(start3,stop3,step3))+list(range(start4,stop4,step4))+"add more if you want"
x[D1,:][:,D2]

the effect is to select out the black regions in this Tartan pattern, from the whole cloth.

arbitary cut

for example, test is a 2D array.

D1 and D2 are some list of index in column and row. We wannt some cut

import numpy as np
test=np.random.random((20,20))
D1=list(range(1,8,2))+list(range(1,9,3))
D2=list(range(1,9,3))+list(range(2,10,3))
print(test[D1,:].shape)
print(test[:,D2].shape)
# test[D1,D2] will create error
output=test[D1,:][:,D2]
type(output)
output.shape

However, it is still unclear, why doesn't test[D1,D2] work.

Upvotes: 0

abarnert
abarnert

Reputation: 365777

Concatenating the two lists, as in Jonas's answer, is the simplest solution, and usually the best.

If you're worried about making temporary lists, you can do something slightly more complicated, like:

[elem for i, elem in enumerate(x) 
 if i in range(start1, stop1, step1) or i in range(start2, stop2, step2)]

… or:

list(itertools.chain(itertools.islice(x, start1, stop1, step1),
                     itertools.islice(x, start2, stop2, step2)))

However, I'd expect either one to be a whole lot slower unless the two sublists are so huge that memory allocation time dominates everything, and of course they're a lot more complicated and less readable.

The only real advantage of either of these solutions is if you don't actually need the list, you can turn them into lazy iterators easily:

(elem for i, elem in enumerate(x) 
 if i in range(start1, stop1, step1) or i in range(start2, stop2, step2))

itertools.chain(itertools.islice(x, start1, stop1, step1),
                itertools.islice(x, start2, stop2, step2))

(In fact, the second one is just the lazy equivalent of Jonas's answer: islice(x, start1, stop1, step1) does the same thing as x[start1:stop1:step1], and chain(a, b) does the same thing as a + b.)

Upvotes: 0

son520804
son520804

Reputation: 483

Concatenate is a great way, or alternatively, you can join the two lists

part1 = x[start1:stop1:step1]
part2 = x[start2:stop2:step2]
mergedlist = part1 + part2

mergedlist = list(set(part1 + part2))

This will create a merged list, with a shallow copy of the items in the first list, followed by a shallow copy of the items in the second list.

If you want deep copy, you may use copy.deepcopy commands.

Upvotes: -2

Giorgi Jambazishvili
Giorgi Jambazishvili

Reputation: 743

This operation is also pretty easy in python. Once you've defined the list you can do your like this:

new_list = lst[start1:stop1:step1] + lst[start2:stop2:step2]

hope this helps.

Upvotes: 1

Jonas
Jonas

Reputation: 1573

You can concatenate two arrays (lists) like this: x[start1:stop1:step1] + x[start2:stop2:step2]

Upvotes: 2

Related Questions