Python:具有间隙的切片的语法较短?

时间:2012-12-12 14:39:31

标签: python slice

假设我想从Python中的列表中获取第一个元素,第3个到第200个元素,以及通过步骤大小3的最后一个元素的第201个元素。

一种方法是使用不同的索引和连接:

new_list = old_list[0:1] + old_list[3:201] + old_list[201::3]

有没有办法只在old_list上使用一个索引来执行此操作?我想要类似下面的内容(我知道这在语法上不起作用,因为列表索引不能是列表,因为Python不幸doesn't have slice literals;我只是在寻找一些接近的东西:

new_list = old_list[[0, 3:201, 201::3]]

我可以通过切换到NumPy数组来实现其中的一些,但我对如何为本机Python列表执行此操作更感兴趣。我也可以创建a slice maker或类似的东西,也可能是强力的手臂,给我一个等效的切片对象来表示我所有想要的切片的组成。

但我正在寻找一些不涉及创建新类来管理切片的东西。我想简单地连接切片语法并将其提供给我的列表,让列表理解它意味着分别获取切片并最终连接它们各自的结果。

6 个答案:

答案 0 :(得分:5)

切片制作者对象(例如来自您的其他问题的SliceMakernp.s_)可以接受多个以逗号分隔的切片;它们作为tuple slice或其他对象收到:

from numpy import s_
s_[0, 3:5, 6::3]
Out[1]: (0, slice(3, 5, None), slice(6, None, 3))

NumPy将其用于多维数组,但您可以将其用于切片连接:

def xslice(arr, slices):
    if isinstance(slices, tuple):
        return sum((arr[s] if isinstance(s, slice) else [arr[s]] for s in slices), [])
    elif isinstance(slices, slice):
        return arr[slices]
    else:
        return [arr[slices]]
xslice(list(range(10)), s_[0, 3:5, 6::3])
Out[1]: [0, 3, 4, 6, 9]
xslice(list(range(10)), s_[1])
Out[2]: [1]
xslice(list(range(10)), s_[:])
Out[3]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

答案 1 :(得分:0)

你最好自己编写自己的序列类型。

>>> L = range(20)
>>> L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> operator.itemgetter(*(range(1, 5) + range(10, 18, 3)))(L)
(1, 2, 3, 4, 10, 13, 16)

让你开始:

>>> operator.itemgetter(*(range(*slice(1, 5).indices(len(L))) + range(*slice(10, 18, 3).indices(len(L)))))(L)
(1, 2, 3, 4, 10, 13, 16)

答案 2 :(得分:0)

为什么不为您的目的创建自定义切片

>>> from itertools import chain, islice
>>> it = range(50)
>>> def cslice(iterable, *selectors):
    return chain(*(islice(iterable,*s) for s in selectors))

>>> list(cslice(it,(1,5),(10,15),(25,None,3)))
[1, 2, 3, 4, 10, 11, 12, 13, 14, 25, 28, 31, 34, 37, 40, 43, 46, 49]

答案 3 :(得分:0)

不确定这是否"更好",但它确实有效,为什么不......

{{1}}

它可能很慢(特别是与链相比),但它是基本的python(3.5.2用于测试)

答案 4 :(得分:0)

您可以扩展list以允许多个切片和索引:

class MultindexList(list):
    def __getitem__(self, key):
        if type(key) is tuple or type(key) is list:
            r = []
            for index in key:
                item = super().__getitem__(index)
                if type(index) is slice:
                    r += item
                else:
                    r.append(item)
            return r
        else:
            return super().__getitem__(key)


a = MultindexList(range(10))
print(a[1:3])             # [1, 2]
print(a[[1, 2]])          # [1, 2]
print(a[1, 1:3, 4:6])     # [1, 1, 2, 4, 5]

答案 5 :(得分:0)

$myVal= "C,6,11";
$garray = array_map('intval', explode(',', $myVal));
import numpy as np
a = list(range(15, 50, 3))

# %%timeit -n 10000 -> 41.1 µs ± 1.71 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
[a[index] for index in np.r_[1:3, 5:7, 9:11]]
---
[18, 21, 30, 33, 42, 45]
import numpy as np
a = np.arange(15, 50, 3).astype(np.int32)

# %%timeit -n 10000 -> 31.9 µs ± 5.68 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
a[np.r_[1:3, 5:7, 9:11]]
---
array([18, 21, 30, 33, 42, 45], dtype=int32)

似乎使用 numpy 是一种更快的方法。

ecatmur 的答案中添加 numpy 部分。

import numpy as np
a = np.arange(15, 50, 3).astype(np.int32)

# %%timeit -n 10000 -> 7.17 µs ± 1.17 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
slices = np.s_[1:3, 5:7, 9:11]
np.concatenate([a[_slice] for _slice in slices])
---
array([18, 21, 30, 33, 42, 45], dtype=int32)