3

I was wondering what would be an efficient an elegant way of slicing a python list based on the index. In order to provide a minimal example:

temp = ['a','b','c','d']

index_needed=[0,2]

How can I slice the list without the loop?

expected output

output_list =['a','c']

I have a sense that there would be a way but haven't figured out any. Any suggestions?

mad_
  • 8,121
  • 2
  • 25
  • 40
  • Possible duplicate of [Understanding Python's slice notation](https://stackoverflow.com/questions/509211/understanding-pythons-slice-notation) – John Stark Aug 23 '18 at 14:29
  • 1
    @JohnStark I don't think you have gone to the details of the question. I don't have a fixed start, stop or step params. I have an index list which I can use to slice it into two lists may be. Definitely not a duplicate – mad_ Aug 23 '18 at 14:31
  • Please don't change the question once you have an answer. This means answerers and potential answers are looking at a moving target. – jpp Aug 23 '18 at 14:41
  • 1
    Possible duplicate of [Picking out items from a python list which have specific indexes](https://stackoverflow.com/questions/724856/picking-out-items-from-a-python-list-which-have-specific-indexes) – Olivier Melançon Aug 23 '18 at 14:42
  • Lists can only be indexed with a scalar or slice. So some sort of iteration is required. It's numpy arrays that can index with a list. – hpaulj Aug 23 '18 at 19:23

3 Answers3

7

First, note that indexing in Python begins at 0. So the indices you need will be [0, 2].

You can then use a list comprehension:

temp = ['a', 'b', 'c', 'd']
idx = [0, 2]

res = [temp[i] for i in idx]            # ['a', 'c']

With built-ins, you may find map performs better:

res = map(temp.__getitem__, idx)        # ['a', 'c']

Since you are using Python 2.7, this returns a list. For Python 3.x, you would need to pass the map object to list.


If you are looking to avoid a Python-level loop altogether, you may wish to use a 3rd party library such as NumPy:

import numpy as np

temp = np.array(['a', 'b', 'c', 'd'])
res = temp[idx]

# array(['a', 'c'], 
#       dtype='<U1')

res2 = np.delete(temp, idx)

# array(['b', 'd'], 
#       dtype='<U1')

This returns a NumPy array, which you can then be converted to a list via res.tolist().

jpp
  • 159,742
  • 34
  • 281
  • 339
1

Use this :

temp = ['a','b','c','d']

temp[0:4:2]

#Output
['a', 'c']

Here first value is starting index number which is (Included) second value is ending index number which is (Excluded) and third value is (steps) to be taken.

Happy Learning...:)

Idrisi_Kasim
  • 81
  • 1
  • 2
0

An alternative that pushes the work to the C layer on CPython (the reference interpreter):

from operator import itemgetter

temp = ['a','b','c','d']

index_needed=[0,2]

output_list = itemgetter(*index_needed)(temp)

That returns tuple of the values; if list is necessary, just wrap in the list constructor:

output_list = list(itemgetter(*index_needed)(temp))

Note that this only works properly if you need at least two indices; itemgetter is variable return type based on how it's initialized, returning the value directly when it's passed a single key to pull, and a tuple of values when passed more than one key.

It's also not particularly efficient for one-off uses. A more common use case would be if you had an iterable of sequences (typically tuples, but any sequence works), and don't care about them. For example, with an input list of:

allvalues = [(1, 2, 3, 4),
             (5, 6, 7, 8)]

if you only wanted the values from index 1 and 3, you could write a loop like:

for _, x, _, y in allvalues:

where you unpack all the values but send the ones you don't care about to _ to indicate the lack of interest, or you can use itemgetter and map to strip them down to what you care about before the unpack:

from future_builtins import map  # Because Py2's map is terrible; not needed on Py3

for x, y in map(itemgetter(1, 3), allvalues):

The itemgetter based approach doesn't care if you have more than four items in a given element of allvalues, while manual unpacking would always require exactly four; which is better is largely based on your use case.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271