从列表或元组中明确选择项目


120

我有以下Python列表(也可以是元组):

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

我可以说

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

如何显式挑选索引没有特定模式的项目?例如,我要选择[0,2,3]。或者,从1000个很大的清单中,我要选择[87, 342, 217, 998, 500]。是否有一些Python语法可以做到这一点?看起来像这样:

>>> myBigList[87, 342, 217, 998, 500]

1
似乎是重复的。另一个问题的投票率更高,但这似乎在时机上有更好的答案。
AnnanFay

Answers:


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

我将答案与python 2.5.2进行了比较:

  • 19.7微秒: [ 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] )

请注意,在Python 3中,第1个已更改为与第4个相同。


另一种选择是以a开头,numpy.array它允许通过列表或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])

tuple不工作方式相同那些片。


2
最好作为list comp,[myBigList[i] for i in [87, 342, 217, 998, 500]]但是我最喜欢这种方法。
zeekay 2011年

@MedhatHelmy那已经在答案中了。from operator import itemgetter的初始化部分中使用的第三个选项python -mtimeit
Dan D.

我想知道,仅从语言设计的角度来看,myBigList[(87, 342, 217, 998, 500)]myBigList使用普通的python 时为什么不起作用list?当我尝试时,我得到了TypeError: list indices must be integers or slices, not tuple。这比输入理解要容易得多-是否涉及语言设计/实现问题?
sparc_spread

@sparc_spread,这是因为lists在Python中仅接受整数或切片。传递整数可确保从现有列表中仅检索一项。传递切片可确保检索到一部分,但传递元组就像将data-type(tuple)作为参数传递给另一个list在语法上不正确的data-type()。
amanb

48

那这个呢:

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

2
到目前为止,这是最性感的。爱那个operator模块!
詹森主义2011年

10

它不是内置的,但是如果您愿意,可以创建一个将元组作为“索引”的list的子类:

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]

印刷

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

2
(+1)整洁的解决方案!有了这个扩展,在Python中处理数组开始看起来像R或Matlab。
阿萨德·易卜拉欣2014年

7

也许列表理解是按顺序进行的:

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

产生:

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

那是您要找的东西吗?


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

您也可以创建自己的List类,该类支持将元组用作__getitem__要执行的操作的参数myList[(2,2,1,3)]


尽管这样做有效,但直接调用魔术变量通常不是一个好主意。最好使用列表理解或类似的帮助器模块operator
詹森主义2011年

@jathanism:我必须尊重地不同意。尽管如果您担心前向兼容性(而不是公共/私有),那么我绝对可以看到您的来历。
ninjagecko 2011年

那就是我来自哪里。:)之后,这也是使用len(myList)over 更好的相同原因myList.__len__()
詹森(Jathanism)2011年

一个创造性的解决方案。我认为调用魔术变量并不是一个坏主意。程序员根据编程情况选择自己喜欢的方式。
崔雅各(CUI)

2

我只想指出,即使itemgetter的语法看起来也很整洁,但是在大型列表上执行时有点慢。

import timeit
from operator import itemgetter
start=timeit.default_timer()
for i in range(1000000):
    itemgetter(0,2,3)(myList)
print ("Itemgetter took ", (timeit.default_timer()-start))

物品获取者1.065209062149279

start=timeit.default_timer()
for i in range(1000000):
    myList[0],myList[2],myList[3]
print ("Multiple slice took ", (timeit.default_timer()-start))

多个切片花费0.6225321444745759


第一个代码段,请添加,myList = np.array(range(1000000))否则会出错。
Cloud Cho

1

另一个可能的解决方案:

sek=[]
L=[1,2,3,4,5,6,7,8,9,0]
for i in [2, 4, 7, 0, 3]:
   a=[L[i]]
   sek=sek+a
print (sek)

0

当你有一个布尔numpy数组时,就像 mask

[mylist[i] for i in np.arange(len(mask), dtype=int)[mask]]

适用于任何序列或np.array的lambda:

subseq = lambda myseq, mask : [myseq[i] for i in np.arange(len(mask), dtype=int)[mask]]

newseq = subseq(myseq, mask)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.