Python List Slicing with Arbitrary Indices

PythonListSlice

Python Problem Overview


Is there a better way to extract arbitrary indices from a list in python?

The method I currently use is:

a = range(100)
s = [a[i] for i in [5,13,25]]

Where a is the array I want to slice, and [5,13,25] are the elements that I want to get. It seems much more verbose than the Matlab equivalent:

a = 0:99;
s = a([6,14,26])

Python Solutions


Solution 1 - Python

>>> from operator import itemgetter
>>> a = range(100)
>>> itemgetter(5,13,25)(a)
(5, 13, 25)

Solution 2 - Python

If you are a Matlab user, but want to use Python, check out numpy:

In [37]: import numpy as np

In [38]: a = np.arange(100)

In [39]: s = a[[5,13,25]]

In [40]: s
Out[40]: array([ 5, 13, 25])

Here is a comparison of NumPy and Matlab, and here is a table of common Matlab commands and their equivalents in NumPy.

Solution 3 - Python

There is no "ready made" way - the way you do it is quite ingenuous, and you could use it. If you have a lot of that trough your code, you might want to use a subclass of list that would use a syntax just like matlabs - it can be done in a few lines code, the major burden is that you'd have to work always use this new class instead of the built-in lists.

class MyList(list):
    def __getitem__(self, index):
        if not isinstance(index, tuple):
            return list.__getitem__(self, index)
        return [self[i] for i in index]

And on the console:

>>> m = MyList(i * 3 for i in range(100))
>>> m[20, 25,60]
[60, 75, 180]

Solution 4 - Python

Here is a more robust version of the excellent accepted @John La Rooy answer. It passes the provided doctests. It always returns a list.

def slice_by_index(lst, indexes):
    """Slice list by positional indexes.

    Adapted from https://stackoverflow.com/a/9108109/304209.

    Args:
        lst: list to slice.
        indexes: iterable of 0-based indexes of the list positions to return.

    Returns:
        a new list containing elements of lst on positions specified by indexes.

    >>> slice_by_index([], [])
    []
    >>> slice_by_index([], [0, 1])
    []
    >>> slice_by_index(['a', 'b', 'c'], [])
    []
    >>> slice_by_index(['a', 'b', 'c'], [0, 2])
    ['a', 'c']
    >>> slice_by_index(['a', 'b', 'c'], [0, 1])
    ['a', 'b']
    >>> slice_by_index(['a', 'b', 'c'], [1])
    ['b']
    """
    if not lst or not indexes:
        return []
    slice_ = itemgetter(*indexes)(lst)
    if len(indexes) == 1:
        return [slice_]
    return list(slice_)

Solution 5 - Python

It seems like you would do:

    a = list(range(99)) 
    s = [a[5], a[13], a[25]] 

this seems to be almost identical to the matlab version.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBen HamnerView Question on Stackoverflow
Solution 1 - PythonJohn La RooyView Answer on Stackoverflow
Solution 2 - PythonunutbuView Answer on Stackoverflow
Solution 3 - PythonjsbuenoView Answer on Stackoverflow
Solution 4 - PythonDennis GolomazovView Answer on Stackoverflow
Solution 5 - PythonJoel CornettView Answer on Stackoverflow