我希望将一个列表作为输入,然后创建另一个列表,其中包含原始列表中相邻元素的元组(或子列表),环绕开始和结束元素。输入/输出将如下所示:
l_in = [0, 1, 2, 3]
l_out = [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
我的问题与另一个标题为 getting successive adjacent elements of a list 的问题密切相关。 ,但是这个其他问题没有考虑结束元素的环绕,并且只处理元素对而不是三元组。
我有一个更长的方法来做到这一点,涉及旋转双端队列并将它们压缩在一起:
from collections import deque
l_in = [0, 1, 2, 3]
deq = deque(l_in)
deq.rotate(1)
deq_prev = deque(deq)
deq.rotate(-2)
deq_next = deque(deq)
deq.rotate(1)
l_out = list(zip(deq_prev, deq, deq_next))
# l_out is [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
但是,我觉得可能有一种更优雅(和/或有效)的方法来使用其他内置的 Python 功能来做到这一点。例如,如果 deque
的 rotate()
函数返回旋转列表而不是就地修改它,则这可能是单行或两行(尽管这将旋转列表压缩在一起的方法可能不是最有效的)。我怎样才能更优雅和/或更有效地完成这个任务?
最佳答案
一种方法可能是使用 itertools
与 more_itertools.windowed
结合:
import itertools as it
import more_itertools as mit
l_in = [0, 1, 2, 3]
n = len(l_in)
list(it.islice(mit.windowed(it.cycle(l_in), 3), n-1, 2*n-1))
# [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
这里我们生成了一个无限循环sliding windows并切片所需的子集。
<小时/>FWIW,这里是后一个代码的抽象,用于给定任何可迭代输入的通用、灵活的解决方案,例如range(5)
、"abcde"
、iter([0, 1, 2, 3])
等:
def get_windows(iterable, size=3, offset=-1):
"""Return an iterable of windows including an optional offset."""
it1, it2 = it.tee(iterable)
n = mit.ilen(it1)
return it.islice(mit.windowed(it.cycle(it2), size), n+offset, 2*n+offset)
list(get_windows(l_in))
# [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]
list(get_windows("abc", size=2))
# [('c', 'a'), ('a', 'b'), ('b', 'c')]
list(get_windows(range(5), size=2, offset=-2))
# [(3, 4), (4, 0), (0, 1), (1, 2), (2, 3)]
注:more-itertools
是一个单独的库,可以通过以下方式轻松安装:
> pip install more_itertools
关于python - 在Python中创建另一个列表的相邻元素的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45743800/