Python任意索引列表切片

64

有没有更好的方法从 Python 列表中提取任意索引?

我目前使用的方法是:

a = range(100)
s = [a[i] for i in [5,13,25]]

我想切片的数组为a,而[5,13,25]是我想获取的元素。它似乎比Matlab的等效写法更冗长:

a = 0:99;
s = a([6,14,26])

9
“这似乎比Matlab更冗长。” 它们是不同的编程语言。你期望什么呢?Python比Java更简洁。 - S.Lott
Python的索引是从0开始的。你的5表示第六个元素。如果使用基于1的语言,则会有一个6。那么Matlab为什么需要4呢?难道它是从-1开始的吗? - John Machin
2
这种方式实际上非常易读,我很喜欢它。 - a06e
5个回答

75
>>> from operator import itemgetter
>>> a = range(100)
>>> itemgetter(5,13,25)(a)
(5, 13, 25)

12
如果使用列表作为索引,请注意以下边界情况:indexes = [1,]; itemgetter(*indexes)(a) ----> 返回一个整数,而不是元组。 - rrauenza
2
谢谢!通过这个函数,我第一次遇到了真正需要使用解包 * 运算符的情况。 - pbarill
3
很好,我希望这是默认行为 - 如果它要费力告诉我它不能接受元组索引,那么它也可以先尝试使用元组。我来到这里是在以类似的方式寻址IPython集群节点后习惯了这个想法。 - Darren Ringer
8
请注意,@DarrenRinger在这里的意思是,如果您想要的索引在列表中,则可以编写itemgetter(*indices)(list) - Bar

36

14

并没有“现成的”方法 - 你所做的方法相当巧妙,你可以使用它。 如果你在代码中有很多这样的东西,你可能想使用一个继承于list的子类,该子类将使用与matlab类似的语法 - 它可以用几行代码完成,主要的负担是你必须始终使用这个新类而不是内置的列表。

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

而在控制台上:

>>> m = MyList(i * 3 for i in range(100))
>>> m[20, 25,60]
[60, 75, 180]

4

以下是优秀的被接受答案John La Rooy所做版本的更强壮的版本(参考答案链接)。它通过提供的doctests测试。它总是返回一个列表。

def slice_by_index(lst, indexes):
    """Slice list by positional indexes.

    Adapted from https://dev59.com/vmox5IYBdhLWcg3wl1T4#9108109.

    Args:
        lst: list to slice.
        indexes: iterable of 0-based indexes of the list positions to return.

    Returns:
        a new list containing elements of lst on positions specified by indexes.

    >>> slice_by_index([], [])
    []
    >>> slice_by_index([], [0, 1])
    []
    >>> slice_by_index(['a', 'b', 'c'], [])
    []
    >>> slice_by_index(['a', 'b', 'c'], [0, 2])
    ['a', 'c']
    >>> slice_by_index(['a', 'b', 'c'], [0, 1])
    ['a', 'b']
    >>> slice_by_index(['a', 'b', 'c'], [1])
    ['b']
    """
    if not lst or not indexes:
        return []
    slice_ = itemgetter(*indexes)(lst)
    if len(indexes) == 1:
        return [slice_]
    return list(slice_)

1

看起来你会做:

    a = list(range(99)) 
    s = [a[5], a[13], a[25]] 

这似乎与Matlab版本几乎完全相同。


如果我猜的话,可能是因为这个答案在Python 3中不起作用(a不可索引)。 - Joel Cornett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接