在python中访问列表或字符串的非连续元素

Posted

技术标签:

【中文标题】在python中访问列表或字符串的非连续元素【英文标题】:Accessing non-consecutive elements of a list or string in python 【发布时间】:2013-10-08 08:11:15 【问题描述】:

据我所知,这并不是官方不可能的,但是否有“技巧”通过切片访问列表的任意非顺序元素?

例如:

>>> L = range(0,101,10)
>>> L
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

现在我希望能够做到

a,b = L[2,5]

这样a == 20b == 50

除了两个陈述之外的另一种方法是愚蠢的:

a,b = L[2:6:3][:2]

但这根本无法扩展到不规则的间隔。

也许使用我想要的索引进行列表理解?

[L[x] for x in [2,5]]

我很想知道针对这个常见问题的建议。

【问题讨论】:

a,b = L[2],L[5]? @roippi - 这确实让它看起来很简单,但我想将它直接应用于返回列表的函数的输出,而不需要调用函数两次或将其重新分配给变量和然后抓住。 我倾向于说你的列表理解是你能做的最好的。或者,如果您不需要实际列表,请使用生成器表达式,就像在 Shashank Gupta 的回答中一样(尽管如果您只需要一次,您可以将 genexp 内联,而不是创建一个函数来返回它)。 【参考方案1】:

可能与您正在寻找的最接近的是itemgetter(或查看here 以获取 Python 2 文档):

>>> L = list(range(0, 101, 10))  # works in Python 2 or 3
>>> L
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
>>> from operator import itemgetter
>>> itemgetter(2, 5)(L)
(20, 50)

【讨论】:

@justhalf:嗯,itemgetter 与 Shashank 的答案非常相似,只是已经包含在 Python 标准库中。 这是一个不错的解决方案,但我认为额外的赞成票是因为它来得稍早......我最终选择了不需要import的那个,尽管它主要是将 OP 包装在函数定义中。 @beroe:即使您接受了另一个答案之后,它仍然获得更多的 new 票,因此较早的时间与它无关。我相信我的回答获得更多选票的原因是,有经验的 Python 程序员通常更喜欢使用itemgetter,而不是定义一个新函数。一个导入比一个函数定义更短更简单。 有道理。我喜欢它作为一种解决方案。 (我也投了票;^) 对于 Python 3,第一行将更改为 >>> L = list(range(0, 101, 10)) 以执行“相同”操作。【参考方案2】:

如果你可以使用numpy,你可以这样做:

>>> import numpy
>>> the_list = numpy.array(range(0,101,10))
>>> the_indices = [2,5,7]
>>> the_subset = the_list[the_indices]
>>> print the_subset, type(the_subset)
[20 50 70] <type 'numpy.ndarray'>
>>> print list(the_subset)
[20, 50, 70]

numpy.arraylist 非常相似,只是它支持更多的运算,例如数学运算以及我们在这里看到的任意索引选择。

【讨论】:

我认为它不是被接受的答案的原因是因为(a)它有更多的膨胀,并且(b)它不那么普遍。 (a): numpy 是一个 huge 库,这个答案把整个东西都拉进去了。(也许from numpy import array?) (b): numpy 特别是 对于数学运算,因此对于专注于后端 Web 开发的人来说不太熟悉。 itemgetter 更接近于覆盖更广泛受众的“裸”Python。 from numpy import array 仍然会加载整个 numpy 包,我相信。但你是对的,如果列表不用于数学运算,这可能有点矫枉过正。【参考方案3】:

这样的?

def select(lst, *indices):
    return (lst[i] for i in indices)

用法:

>>> def select(lst, *indices):
...     return (lst[i] for i in indices)
...
>>> L = range(0,101,10)
>>> a, b = select(L, 2, 5)
>>> a, b
(20, 50)

函数的工作方式是返回一个generator object,它可以像任何类型的 Python 序列一样进行迭代。

正如@justhalf 在 cmets 中指出的那样,您的调用语法可以通过定义函数参数的方式进行更改。

def select(lst, indices):
    return (lst[i] for i in indices)

然后你可以调用函数:

select(L, [2, 5])

或您选择的任何列表。

更新:我现在建议改用operator.itemgetter,除非你真的需要生成器的惰性求值功能。见John Y's answer。

【讨论】:

您认为将函数定义为select(lst, indices) 并将其称为select(L, [2,5]) 会更好吗? @justhalf @Shashank 快速提问。 "*indices" 参数只是 "*args" 对吗?但名称不同? @HalcyonAbrahamRamirez 是的,完全正确。 :) 这是一个非常古老的答案,除非需要生成器的惰性求值功能,否则我建议使用 operator.itemgetter【参考方案4】:

为了完整起见,原始问题的方法非常简单。如果L 本身就是一个函数,您可能希望将其包装在一个函数中,或者事先将函数结果分配给一个变量,这样就不会重复调用它:

[L[x] for x in [2,5]]

当然它也适用于字符串...

["ABCDEF"[x] for x in [2,0,1]]
['C', 'A', 'B']

【讨论】:

【参考方案5】:

其他答案都不适用于multidimensional object 切片。恕我直言,这是最通用的解决方案(使用numpy):

numpy.ix_ 允许您同时选择数组所有维度中的任意索引。

例如:

>>> a = np.arange(10).reshape(2, 5) # create an array
>>> a
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])
>>> ixgrid = np.ix_([0, 1], [2, 4]) # create the slice-like grid
>>> ixgrid
(array([[0],
       [1]]), array([[2, 4]]))
>>> a[ixgrid]                       # use the grid to slice a
array([[2, 4],
       [7, 9]])

【讨论】:

是的,这太糟糕了,python 没有更好的对数组类型数据的基本支持而不需要 numpy

以上是关于在python中访问列表或字符串的非连续元素的主要内容,如果未能解决你的问题,请参考以下文章

如何在python列表中查找某个元素的索引

R语言_list()函数用法

Python---列表

python怎么将列表中元素分配成三份(无需连续),列举出所有的方案?

第三章-列表简介

详解Python列表和元组