使Python切片理智(正/向前+无Nones +无负指数+在界限内)

时间:2015-11-26 16:44:11

标签: 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)

1 个答案:

答案 0 :(得分:3)

使用.blink方法。

  

S.indices(len) - &gt; (开始,停止,跨步)

     

假设长度为len的序列,计算起始和停止索引,以及由S描述的扩展切片的步长。超出边界索引的裁剪方式与正常切片的处理一致。