# How to extract multiple slices in an array?

## Question:

I need to extract data from multiple positions in an array.

A simple array would be:-

``````listing = (4, 22, 24, 34, 46, 56)
``````

I am familiar with slicing. For instance:-

``````listing[0:3]
``````

would give me:-

``````(4, 22, 24)
``````

However I am unable to get out multiple slices. For instance:-

``````listing[0:3, 4:5]
``````

gives me

``````TypeError: tuple indices must be integers not tuples
``````

Despite Searching two Python books and the Internet I cannot work out the syntax to use.

You can slice twice and join them.

``````listing[0:3] + listing[4:5]
``````

Try:

``````>>> listing = (4, 22, 24, 34, 46, 56)
>>> listing[0:3], listing[4:5]
((4, 22, 24), (46,))
``````

If you have the index numbers of the slices you need you can just grab them with a loop contained in a list.

``````index_nums = [0,2,4]
output = [listing[val] for val in index_nums]
``````

This will return [4,24,46]

I needed this exact construct for a pandas situation. I used a helper generator.

``````Python 3.7.4 (v3.7.4:e09359112e, Jul  8 2019, 14:54:52)
[Clang 6.0 (clang-600.0.57)] on darwin

>>> listing = (4, 22, 24, 34, 46, 56)
>>> def multislice(a,sl):
...     for si in sl:
...         yield a[si]
...
>>> list(multislice(listing,[slice(0,3),slice(4,5)]))
[(4, 22, 24), (46,)]
``````

And by extension, how to do many various slices.

``````>>> list(multislice(listing,[slice(0,3),slice(4,5),slice(3,None)]))
[(4, 22, 24), (46,), (34, 46, 56)]
``````

With a class, you can do this

``````class Listing():
def __init__(self, *args):
self.array = args
def __getitem__(self, slices):
return sum((self.array[s] for s in slices), ())

listing = Listing(4, 22, 24, 34, 46, 56)
listing[0:3, 4:5]   # (4, 22, 24, 46)
``````

The constructs `sum((...), ())` joins the tuples (`()+()+()`) and thus flattens the output.

## update

A version that returns a list instead of a tuple, and that handles both single index and slices (e.g. `` or `[0:1]`)

``````class Listing(list):
def __getitem__(self, s):
get = super(Listing, self).__getitem__
return sum(map(get,s), []) if hasattr(s,'__iter__') else get(s)

listing = Listing([4, 22, 24, 34, 46, 56])
listing[0:3, 4:5]   # [4, 22, 24, 46]
``````

This is a slightly improved version of Friedrich’s amazing answer. Here it is:

``````class Advanced_List():
def __init__(self, *args, is_list = True):
self.array = list(args) if is_list else args
self.islist = is_list
def __iter__(self):
yield from self.array
def __getitem__(self, slices):
return sum([[self.array[s]] if type(s) == int else self.array[s] for s in slices], []) if type(slices) == tuple else self.array[slices] #No more multidimensional shorthand!
def __str__(self):
return str(self.array)
def __repr__(self):
return str(self)[1:-1]
#Look at the __getitem__ method
``````

# EDIT 1:

Changed the `__getitem__` line. Now, no comma is needed for a single slice!

When working `numpy` arrays, you can use `np.r_` to generate indices

``````>>> np.array([4, 22, 24, 34, 46, 56])[np.r_[0:3, 4:5]]
array([ 4, 22, 24, 46])
``````

This can handle multiple slices of the form like `1`, `0:3`, `:3` or `-3:-1`, however not properly those `:`, `1:` or `-3:`, `:-3` .

You could use the `operator.itemgetter()` function along with the built-in `slice` class to do something very succinct and readable along these lines:

``````from operator import itemgetter

listing = (4, 22, 24, 34, 46, 56)

items = itemgetter(slice(0,3), slice(4,5))(listing)

print(items)  # -> ((4, 22, 24), (46,))
``````

Elaborating on `Advanced_List` above, I’d like to propose a type-checked version:
Notice that slicing returns an instance of the same, so you can do things like

``````x=Sliceable([1,2,3,4,5,6,7,8,9])
x[1:3,3:,4:][1,2,5:][:3]
``````
``````from typing import Iterable, Union, Any, Tuple

class Sliceable():
""" A multi-sliceable wrapper for iterables """
def __init__(self, array: Union[Iterable[Any],Any]):
try:
self.array = tuple(array)
except TypeError:
self.array=(array,)

def __iter__(self):
yield from self.array

def __getitem__(self, slices:Union[int,slice,Tuple[Union[int,slice],...]]) -> 'Sliceable':
if isinstance(slices,tuple):
return self.__class__(sum(((self.array[s],) if isinstance(s,int) else self.array[s] for s in slices),()))
return self.__class__(self.array[slices])

def __str__(self):
return str(self.array)

def __repr__(self):
return f"{self.__class__.__name__}({self.array})"
``````
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.