从列表或元组中显式选择项目

Posted

技术标签:

【中文标题】从列表或元组中显式选择项目【英文标题】:Explicitly select items from a list or tuple 【发布时间】:2011-10-01 17:02:47 【问题描述】:

我有以下 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]

【问题讨论】:

This 似乎是重复的。另一个问题有更多的赞成票,但这似乎在时间上有更好的答案。 这能回答你的问题吗? Access multiple elements of list knowing their index 【参考方案1】:
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 微秒:map(myBigList.__getitem__, (87, 342, 217, 998, 500))

22.7 微秒:itemgetter(87, 342, 217, 998, 500)(myBigList)

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

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


另一种选择是从numpy.array 开始,它允许通过列表或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 的工作方式与切片不同。

【讨论】:

最好作为列表比较,[myBigList[i] for i in [87, 342, 217, 998, 500]],但我最喜欢这种方法。 @MedhatHelmy 这已经在答案中了。第三个选项在python -mtimeit的初始化部分使用了from operator import itemgetter 我想知道,仅从语言设计的角度来看,当myBigList 是普通的python list 时,为什么myBigList[(87, 342, 217, 998, 500)] 不起作用?当我尝试时,我得到TypeError: list indices must be integers or slices, not tuple。这比输入理解要容易得多 - 是否涉及语言设计/实现问题? @sparc_spread,这是因为 Python 中的 lists 只接受整数或切片。传递整数可确保从现有列表中仅检索一项。传递一个切片可以确保检索到其中的一部分,但是传递一个元组就像将一个数据类型(tuple)作为参数传递给另一个数据类型(list),这在语法上是不正确的。 @Qbik 因为在 Python 2 中,它不会泄漏循环变量,因为为生成器表达式创建了新范围。 Python 3 不需要这样做,因为列表推导已被更改为这样做。我更喜欢它,因为它可以更轻松地将列表换成任何其他生成器消耗函数。这也是我既不关心字典推导也不关心集合推导的原因。【参考方案2】:

这个呢:

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

【讨论】:

这是迄今为止最性感的。喜欢 operator 模块!【参考方案3】:

也许列表理解是有序的:

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

生产:

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

这就是你要找的吗?

【讨论】:

【参考方案4】:

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

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']

【讨论】:

(+1) 简洁的解决方案!有了这个扩展,在 Python 中处理数组开始看起来更像 R 或 Matlab。【参考方案5】:
>>> map(myList.__getitem__, (2,2,1,3))
('baz', 'baz', 'bar', 'quux')

如果您希望能够做到myList[(2,2,1,3)],您还可以创建自己的List 类,该类支持将元组作为__getitem__ 的参数。

【讨论】:

虽然这可行,但直接调用魔术变量通常不是一个好主意。你最好使用列表理解或像 operator 这样的帮助模块。 @jathanism:我必须恭敬地不同意。虽然如果您担心前向兼容性(而不是公共/私有),我绝对可以看到您来自哪里。 这就是我的来历。 :) 之后,这也是为什么最好使用len(myList) 而不是myList.__len__() 一个创造性的解决方案。我不认为调用魔法变量是一个坏主意。程序员根据编程环境选择自己喜欢的方式。 使用魔法方法通常是不好的,所以最好避免它。除非出于性能原因,否则从来没有必要。如果有任何关于 __getitem__() 的具体内容,请 IDK,但有关其他示例,请参阅 Why does calling Python's 'magic method' not do type conversion like it would for the corresponding operator? 和 Is there any case where len(someObj) does not call someObj's __len__ function?。【参考方案6】:

我只想指出,即使是 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))

Itemgetter 拿了 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

【讨论】:

第一个sn-p,请加myList = np.array(range(1000000)),否则会报错。【参考方案7】:

另一种可能的解决方案:

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)

【讨论】:

【参考方案8】:

当你有一个像 mask 这样的布尔 numpy 数组时经常这样

[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)

【讨论】:

以上是关于从列表或元组中显式选择项目的主要内容,如果未能解决你的问题,请参考以下文章

在 QT 中显式调用paintGL

在另一个 SBT 插件中显式启用 SBT 插件

从Aurelia依赖注入容器中显式请求新实例

如何修复您应该只在 IOS 的应用程序中显式呈现一个导航器

sequelize抛出错误方言需要在express js中显式定义

在 terraform 模块中显式使用提供程序