Python:在定长列表中平移元素

0 投票
7 回答
3874 浏览
提问于 2025-04-17 12:40

我想找一种优雅的方法来写一个简单的函数,这个函数可以把列表中的元素按给定的位数移动,同时保持列表的长度不变,并用默认值填充空出来的位置。以下是这个函数的说明:

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

撰写回答