2

I am looking for an elegant way to slice a list l in python, given a list of ids l_ids. For example, instead of writing

new_list = [l[i] for i in l_ids] 

Write something like (Pseudo code):

new_list = l[*l_ids] 

Is there a similar way to slice lists?

I have the feeling that someone have asked that already, but I couldn't find any reference for it.

Edit: It is OK to assume that all the list items are of the same type?

martineau
  • 119,623
  • 25
  • 170
  • 301
Yuval Atzmon
  • 5,645
  • 3
  • 41
  • 74

5 Answers5

7

You can use operator.itemgetter(*items) like this:

from operator import itemgetter

getter = itemgetter(*lst_ids)
new_list = list(getter(lst))

Also, note that I renamed l variable to lst because it is less ambiguous and should be avoided.

You can implicitly cast the tuple to a list using Python 3 unpacking, as @JonClements commented:

*new_list, = getter(lst)

Finally, since Python 3.5, you can also use extended unpacking:

new_list = [*getter(lst)]
Delgan
  • 18,571
  • 11
  • 90
  • 141
  • If you're going to mention the extended unpacking in 3.5, don't forget that there's other unpacking that'll work in the 3 series (although it's not very pretty) `*new_lst, = getter(lst)` (and since `list()` will work across the board and says what it means - I'd stick with that anyway...) – Jon Clements Jul 10 '16 at 10:41
2

You could use itemgetter

from operator import itemgetter

l = ['a', 'b', 'c', 'd', 'e']
l_ids = [1, 2, 3]
list(itemgetter(*l_ids)(l))

['b', 'c', 'd']

Maximilian Peters
  • 30,348
  • 12
  • 86
  • 99
2

I don't think importing anything is particularly elegant, or pythonic.

List comprehensions work, and I can't see a reason not to use them (or no good reason to import something to do the same thing):

>>> x = [3,5,7,0,1,4,2,6]
>>> y = ['a','b','c','d','e','f','g','h']
>>> nList = [y[i] for i in x]
>>> nList
['d', 'f', 'h', 'a', 'b', 'e', 'c', 'g']

The list comprehension is doing the following:

indexes = [3,5,7,0,1,4,2,6]
data = ['a','b','c','d','e','f','g','h']
nList = []
for index in indexes:
    nList += [data[index]]

The comprehension looks pretty pythonic and elegant to me.

Tim
  • 2,563
  • 1
  • 23
  • 31
  • If the author only need to create such a list once, I think list comprehension is perfectly fine, but `itemgetter()` it a elegant way if it needs to be repeated several times. – Delgan Jul 10 '16 at 10:28
  • @Delgan Ahh, good point. I guess if you have the same list of ids for multiple data lists, it's slower. – Tim Jul 10 '16 at 10:29
1

I would go with itemgetter but you could also map list.__getitem__:

l = ['a', 'b', 'c', 'd', 'e']
l_ids = [1, 2, 3]

new = list(map(l.__getitem__, l_ids))
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • I am not sure method with double leadind and trailing underscore should be used, it is reserved to Python internally, is not it? – Delgan Jul 10 '16 at 10:32
  • It is a matter of opinion, I and lots of other people often use the same logic to avoid having to use lambda calls with map, filters i.e some_set.__contains__ vs lambda st: x in st etc.. – Padraic Cunningham Jul 10 '16 at 10:43
0

If all the list elements are of the same type, it is possible to use numpy:

from numpy import *
new_list = array(l)[l_ids]
Yuval Atzmon
  • 5,645
  • 3
  • 41
  • 74