2015-11-26 64 views
1

在Python中实现可用标准Python语法切片的类时(例如负指数,步进等),有时可能会有所帮助将切片转换成“理智的向前切片”以确定切片的元素。如何以简洁/优雅的形式写出这样的功能?使Python切片正常(正向/正向+无向+负向索引+范围内)

对于“理智的向前切片”,我的意思是等同于初始切片的切片,即所得元素是相同的,但是具有积极的步骤,没有负指数,也没有指数大于对象的长度。

实例(假定10的阵列长度):

slice(None, 4,None) -> slice(0, 4, 1) 
slice( -7, 12, 1) -> slice(3,10, 1) 
slice(None,None, -1) -> slice(0,10, 1) 
slice( 7, 3, -2) -> slice(5, 8, 2) 
slice( 9, 1, -3) -> slice(3,10, 3) 

它不是非常困难的写执行这种变换的功能,但我无法写它简洁。特别是在将“向后切片”转换为等效的“向前切片”时确定起始索引似乎非常麻烦。

工作例如:

def to_sane_slice(s, N): 
    step = s.step if s.step is not None else 1 
    if step == 0: 
     ValueError('Slice step cannot be 0!') 

    # get first index 
    first = s.start 
    if first is None: 
     first = 0 if step > 0 else N-1 
    elif first < 0: 
     first = N+first 
     if first < 0: 
      if step < 0: 
       return slice(0,0,1) 
      first = 0 
    elif first >= N: 
     if step > 0: 
      return slice(0,0,1) 
     first = N-1 
    # get stop index 
    stop = s.stop 
    if stop is None: 
     stop = N if step > 0 else -1 
    elif stop < 0: 
     stop = max(-1, N+stop) 

    # check for etmpy slices 
    if (stop-first)*step <= 0: 
     return slice(0,0,1) 

    if step > 0: 
     return slice(first, min(stop,N), step) 
    elif step == -1: 
     return slice(stop+1, first+1, -step) 
    else: 
     # calculate the new start -- does not have to be next to old stop, since 
     # the stepping might lead elsewhere 
     step = -step 
     dist = first - max(stop,-1) 
     last = first - dist/step * step 
     if dist % step == 0: 
      last += step 
     return slice(last, first+1, step) 



编辑(最终功能):

随着使用slice.indices()到@doublep好心向我指出它变成:

def to_sane_slice(s, N): 
    # get rid of None's, overly large indices, and negative indices (except -1 for 
    # backward slices that go down to first element) 
    start, stop, step = s.indices(N) 

    # get number of steps & remaining 
    n, r = divmod(stop - start, step) 
    if n < 0 or (n==0 and r==0): 
     return slice(0,0,1) 
    if r != 0: # its a "stop" index, not an last index 
     n += 1 

    if step < 0: 
     start, stop, step = start+(n-1)*step, start-step, -step 
    else: # step > 0, step == 0 is not allowed 
     stop = start+n*step 
    stop = min(stop, N) 

    return slice(start, stop, step) 
+0

你看过numpy切片和视图吗? –

+0

我没有看到numpy的连接。 (定制)Python类“切片”可能相当复杂,不需要是任何类型的适当数组(至少在内存方面)。 –

+0

我猜最后应该是9而不是10? –

回答

3

使用slice.indices()方法。

S.indices(LEN) - >(启动,停止,步幅)

假设长度LEN的序列,计算的开始和停止指标,并用S描述的扩展切片的步幅超出界限以与正常切片处理一致的方式裁剪索引。

+0

这还不是我所要求的,但它有助于编写更简洁和优雅的函数。 (我怎么能监督这个方法?)所以我想这就是我的问题的答案。 –

+0

此方法是否有任何联机文档? – Eric

+0

@Eric:显然没有。我能找到的最好的[是什么新的](https://docs.python。组织/ 2.3/whatsnew /部分-slices.html)。 – doublep