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

Python:有间隙的切片的较短语法?,python,slice,Python,Slice,假设我想要Python列表中的第一个元素,第三个到第200个元素,第201个元素到最后一个元素,步长为3 一种方法是使用不同的索引和连接: new_list = old_list[0:1] + old_list[3:201] + old_list[201::3] def xslice(arr, slices): if isinstance(slices, tuple): return sum((arr[s] if isinstance(s, slice) else [a

假设我想要Python列表中的第一个元素,第三个到第200个元素,第201个元素到最后一个元素,步长为3

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

new_list = old_list[0:1] + old_list[3:201] + old_list[201::3]
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]
是否有一种方法可以只使用
旧列表中的一个索引来实现这一点?我想要下面这样的东西(我知道这在语法上不起作用,因为列表索引不能是列表,而且Python很不幸;我只是在寻找一些接近的东西):

我可以通过切换到NumPy数组来实现这一点,但我更感兴趣的是如何在原生Python列表中实现这一点。我也可以创建或类似的东西,可能还有强大的手臂,给我一个等价的切片对象来表示所有我想要的切片的组成


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

您最好编写自己的序列类型

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

为什么不;你不能为自己的目的创建一个自定义切片吗

>>> 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]
slice maker对象(例如,您的另一个问题中的
SliceMaker
,或
np.s\uu
)可以接受多个逗号分隔的切片;它们作为
slice
s的
tuple
或其他对象接收:

from numpy import s_
s_[0, 3:5, 6::3]
Out[1]: (0, slice(3, 5, None), slice(6, None, 3))
NumPy将其用于多维数组,但您可以将其用于切片连接:

new_list = old_list[0:1] + old_list[3:201] + old_list[201::3]
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]
不确定这是否“更好”,但它有效,所以为什么不

[y表示x中的x[old_list[slice(*a)]表示x中的y((0,1)、(3201)、(201,None,3))


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

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

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]
似乎使用numpy是一种更快的方法

将numpy部分添加到来自的答案


“不幸的是Python没有切片原语”甚至没有
slice
?对不起,我应该说切片文字,而不是切片原语。也就是说,您不能只是传递语法
(0:10:2)
,就好像它本身就是始终表示索引的某个对象一样。您必须经历制作自己的切片对象的繁琐的额外层,这会破坏切片语法的所有细节。请参阅我的。我会使用
itertools.islice
itertools.chain
来构建这些。您是否查看了我上面包含的与我之前提出的问题的链接?该问题的答案或多或少体现了与您的答案相同的内容,但具有更好的语法,并且不需要
itertools
。我的主要目标是直接按原样传递切片语法。添加将切片表示为元组并将其传递给新对象的语法开销甚至比连接单独的切片更糟糕。@EMS:不,这个答案只是描述了一种轻松创建切片的方法,但它们不能用于索引列表中的元素。Abhijit解决方案可以满足您的需要,您可以将它与另一个答案结合起来,使用类似于:
cslice(it,make_slice[1:5],make_slice[10:15],make_slice[25::3])
@Bakuriu:这就是我的全部观点
cslice
除了链接切片之外什么都不做,这比串联列表要差。在回答中,
tuple
s用作
cslice
的参数。感谢您向我展示
SliceMaker
示例的结果也可以传入。这缓解了这个答案的一些语法膨胀,但还不够。它不适用于
xslice(列表(范围(10)),[1,2,3])
,我的最新版本也不适用。我的第一次修订没有问题,谢谢!改进您的编辑以测试insinstance(…,slice)
,交换后两种情况。这很聪明,但主要用例之一是将“带间隙的切片”传递给多维数量的每个组件,因此,以逗号分隔的值只应用于第一个维度的方式重载getitem是没有帮助的。我认为真正的问题在于,像
::2
3:8
这样的切片语法并不表示文字对象,而且对这些文字没有内置的间隔、范围或集合算法支持。另外,我不确定当元组或其他序列作为索引传递时,是否有任何标准语义来解释它的含义。e、 g.
numpy
主要用于多维索引,而我们在这里使用它来连接索引,这可能会让人困惑。
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)
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)
import numpy as np
def xslice(x, slices):
    """Extract slices from array-like
    Args:
        x: array-like
        slices: slice or tuple of slice objects
    """
    if isinstance(slices, tuple):
        if isinstance(x, np.ndarray):
            return np.concatenate([x[_slice] for _slice in slices])
        else:
            return sum((x[s] if isinstance(s, slice) else [x[s]] for s in slices), [])        
    elif isinstance(slices, slice):
        return x[slices]
    else:
        return [x[slices]]