在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)
你看过numpy切片和视图吗? –
我没有看到numpy的连接。 (定制)Python类“切片”可能相当复杂,不需要是任何类型的适当数组(至少在内存方面)。 –
我猜最后应该是9而不是10? –