在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 == 20
和b == 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.array
与list
非常相似,只是它支持更多的运算,例如数学运算以及我们在这里看到的任意索引选择。
【讨论】:
我认为它不是被接受的答案的原因是因为(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中访问列表或字符串的非连续元素的主要内容,如果未能解决你的问题,请参考以下文章