Python:在定长列表中平移元素
我想找一种优雅的方法来写一个简单的函数,这个函数可以把列表中的元素按给定的位数移动,同时保持列表的长度不变,并用默认值填充空出来的位置。以下是这个函数的说明:
def shift_list(l, shift, empty=0):
"""
Shifts the elements of a list **l** of **shift** positions,
padding new items with **empty**::
>>> l = [0, 1, 4, 5, 7, 0]
>>> shift_list(l, 3)
[0, 0, 0, 0, 1, 4]
>>> shift_list(l, -3)
[5, 7, 0, 0, 0, 0]
>>> shift_list(l, -8)
[0, 0, 0, 0, 0, 0]
"""
pass
你会怎么做呢?任何帮助都非常感谢!
7 个回答
1
有点简单,但工作完成了。
def shift(l, shift, empty=0):
reverse = False
if shift < 0:
reverse = True
shift = abs(shift)
while (shift > 0) :
if reverse:
l.pop(0)
l.append(empty)
else:
l.pop()
l.insert(0, empty)
shift-=1
l = [0, 1, 4, 5, 7, 0]
shift(l, 3)
print l
l = [0, 1, 4, 5, 7, 0]
shift(l, -3)
print l
l = [0, 1, 4, 5, 7, 0]
shift(l, -8)
print l
2
如果你能用一个叫做 deque 的东西来代替列表,那它有一些不错的特点,非常适合解决这个问题。用 deque 从左边操作要比用列表省钱(也就是更快)。另外,它还有一个 maxlen 参数,可以让代码看起来更漂亮,运行得也更快。我觉得用 itertools.repeat
来代替 [empty] * n
在内存和速度上都更有效率。
from collections import deque
from itertools import repeat
def shift_list(l, n, empty=0):
d = deque(l, maxlen=len(l))
if n > 0:
d.extendleft(repeat(empty, min(n, len(l))))
elif n < 0:
d.extend(repeat(empty, min(-n, len(l))))
# return list(d) to pass your doctest, at the cost of performance
return d
不过要提醒一下 -- 虽然遍历 deque 的元素所花的时间和遍历列表差不多,但查找某个元素的时间可能会比较贵(也就是比较慢) -- 这取决于你查找的位置:比如 s[0]
和 s[-1]
查找得很快,而 s[len(s)/2]
查找就比较慢。所以如果你需要查找很多次,考虑换个方法,或者把结果再转回列表。想了解更多,可以看看 这个页面。
3
我会使用切片赋值:
def shift_list(l, shift, empty=0):
src_index = max(-shift, 0)
dst_index = max(shift, 0)
length = max(len(l) - abs(shift), 0)
new_l = [empty] * len(l)
new_l[dst_index:dst_index + length] = l[src_index:src_index + length]
return new_l