Explicitly select items from a list or tuple

391,108

Solution 1

list( myBigList[i] for i in [87, 342, 217, 998, 500] )

I compared the answers with python 2.5.2:

  • 19.7 usec: [ myBigList[i] for i in [87, 342, 217, 998, 500] ]

  • 20.6 usec: map(myBigList.__getitem__, (87, 342, 217, 998, 500))

  • 22.7 usec: itemgetter(87, 342, 217, 998, 500)(myBigList)

  • 24.6 usec: list( myBigList[i] for i in [87, 342, 217, 998, 500] )

Note that in Python 3, the 1st was changed to be the same as the 4th.


Another option would be to start out with a numpy.array which allows indexing via a list or a numpy.array:

>>> import numpy
>>> myBigList = numpy.array(range(1000))
>>> myBigList[(87, 342, 217, 998, 500)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: invalid index
>>> myBigList[[87, 342, 217, 998, 500]]
array([ 87, 342, 217, 998, 500])
>>> myBigList[numpy.array([87, 342, 217, 998, 500])]
array([ 87, 342, 217, 998, 500])

The tuple doesn't work the same way as those are slices.

Solution 2

What about this:

from operator import itemgetter
itemgetter(0,2,3)(myList)
('foo', 'baz', 'quux')

Solution 3

Maybe a list comprehension is in order:

L = ['a', 'b', 'c', 'd', 'e', 'f']
print [ L[index] for index in [1,3,5] ]

Produces:

['b', 'd', 'f']

Is that what you are looking for?

Solution 4

It isn't built-in, but you can make a subclass of list that takes tuples as "indexes" if you'd like:

class MyList(list):

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


seq = MyList("foo bar baaz quux mumble".split())
print seq[0]
print seq[2,4]
print seq[1::2]

printing

foo
['baaz', 'mumble']
['bar', 'quux']

Solution 5

>>> map(myList.__getitem__, (2,2,1,3))
('baz', 'baz', 'bar', 'quux')

You can also create your own List class which supports tuples as arguments to __getitem__ if you want to be able to do myList[(2,2,1,3)].

Share:
391,108
Kit
Author by

Kit

Updated on December 05, 2020

Comments

  • Kit
    Kit over 3 years

    I have the following Python list (can also be a tuple):

    myList = ['foo', 'bar', 'baz', 'quux']
    

    I can say

    >>> myList[0:3]
    ['foo', 'bar', 'baz']
    >>> myList[::2]
    ['foo', 'baz']
    >>> myList[1::2]
    ['bar', 'quux']
    

    How do I explicitly pick out items whose indices have no specific patterns? For example, I want to select [0,2,3]. Or from a very big list of 1000 items, I want to select [87, 342, 217, 998, 500]. Is there some Python syntax that does that? Something that looks like:

    >>> myBigList[87, 342, 217, 998, 500]
    
  • zeekay
    zeekay almost 13 years
    Preferably as a list comp, [myBigList[i] for i in [87, 342, 217, 998, 500]], but I like this approach the best.
  • jathanism
    jathanism almost 13 years
    This is the sexiest so far. Love that operator module!
  • jathanism
    jathanism almost 13 years
    While this works it's usually not a good idea to directly invoke magic variables. You're better off using a list comprehension or a helper module like operator.
  • ninjagecko
    ninjagecko almost 13 years
    @jathanism: I have to respectfully disagree. Though if you are concerned about forward compatibility (as opposed to public/private) I can definitely see where you're coming from.
  • jathanism
    jathanism almost 13 years
    That is where I'm coming from. :) Following that, it's the same reason why it's better to use len(myList) over myList.__len__().
  • Assad Ebrahim
    Assad Ebrahim about 10 years
    (+1) Neat solution! With this extension, handling arrays in Python starts to look much R or Matlab.
  • Jacob CUI
    Jacob CUI about 9 years
    a creative solution.I don't think it's a bad idea to invoke magic variable. programmer selects their preferred way based on programming circumstances.
  • Dan D.
    Dan D. over 8 years
    @MedhatHelmy That's already in the answer. The third option used from operator import itemgetter in the initialization part of python -mtimeit.
  • sparc_spread
    sparc_spread about 8 years
    I wonder, just from a language design perspective, why myBigList[(87, 342, 217, 998, 500)] doesn't work when myBigList is a regular python list? When I try that I get TypeError: list indices must be integers or slices, not tuple. That would be so much easier than typing out the comprehension - is there a language design/implementation issue involved?
  • amanb
    amanb almost 6 years
    @sparc_spread, this is because lists in Python only accept integers or slices. Passing an integer makes sure that only one item is retrieved from an existing list. Passing a slice makes sure a part of it is retrieved, but passing a tuple is like passing a data-type(tuple) as an argument to another data-type(list) which is syntactically incorrect.
  • Cloud Cho
    Cloud Cho over 5 years
    First snippet, please add myList = np.array(range(1000000)) otherwise you will get error.
  • wjandrea
    wjandrea about 3 years
    Using magic methods is generally bad, so it's better to just avoid it. It's never necessary except maybe for performance reasons. IDK if there's anything specific about __getitem__(), but for other examples, see Why does calling Python's 'magic method' not do type conversion like it would for the corresponding operator? and Is there any case where len(someObj) does not call someObj's __len__ function?.
  • ninjagecko
    ninjagecko about 3 years
    Those magic method counterexamples are all about how the magic method implements a "building block" that may be used as part of a more complicated protocol. I see no reason not to use it, since we are not expecting the more complicated protocol (or in this case the method is the protocol basically). Happy to be proven wrong though. Using this will make your code possibly throw IndexError on invalid indices etc. (but than again your code may also work with negative indexes which can be a positive) -- docs.python.org/3/reference/datamodel.html#object.__getitem_‌​_
  • Qbik
    Qbik almost 3 years
    why list( myBigList[i] for i in [87, 342, 217, 998, 500] ) and not [ myBigList[i] for i in [87, 342, 217, 998, 500] ]
  • Dan D.
    Dan D. almost 3 years
    @Qbik Because in Python 2, it does not leak the loop variable as a new scope is created for the generator expression. One does not need to do it for Python 3 as the list comprehension has been changed to do that. I prefer it though as it makes it easier to swap out list for any other generator consuming function. This is also the reason that I don't care for either dictionary comprehensions nor set comprehensions.