Python 从环绕的列表中读取批处理

Python 从环绕的列表中读取批处理,python,Python,我有以下情况。假设我有一个变量batch\u size和一个名为data的列表。我想从数据中提取batch\u size元素,这样当我到达终点时,我就可以绕过去了。换言之: data =[1,2,3,4,5] batch_size = 4 -> [1,2,3,4], [5,1,2,3], [4,5,1,2], ... 有没有一些很好的惯用方法返回这样的切片?开始索引总是batch\u size*batch对数据的长度进行模化,但是如果batch\u size*(batch+1)超出了列表

我有以下情况。假设我有一个变量
batch\u size
和一个名为
data
的列表。我想从
数据
中提取
batch\u size
元素,这样当我到达终点时,我就可以绕过去了。换言之:

data =[1,2,3,4,5]
batch_size = 4
-> [1,2,3,4], [5,1,2,3], [4,5,1,2], ...
有没有一些很好的惯用方法返回这样的切片?开始索引总是
batch\u size*batch
数据的长度进行模化,但是如果
batch\u size*(batch+1)
超出了列表的长度,是否有一种简单的方法从一开始就“环绕”?在这种情况下,我当然可以将两片拼接在一起,但我希望有一种真正干净的方法可以做到这一点


我唯一的假设是
batch\u size

您可以使用
itertools.cycle
和itertools的
grouper
配方

import itertools

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.zip_longest(*args, fillvalue=fillvalue)

data = [1,2,3,4,5]
batch_size = 4
how_many_groups = 5

groups = grouper(itertools.cycle(data), batch_size)
chunks = [next(groups) for _ in range(how_many_groups)]
然后,块的结果是:

[(1, 2, 3, 4),
 (5, 1, 2, 3),
 (4, 5, 1, 2),
 (3, 4, 5, 1),
 (2, 3, 4, 5)]

因此,如果您确实需要这些列表,您必须将其转换为列表(
[列表(下一个(组))

您可以使用
itertools.cycle
和来自itertools的
grouper
配方

import itertools

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.zip_longest(*args, fillvalue=fillvalue)

data = [1,2,3,4,5]
batch_size = 4
how_many_groups = 5

groups = grouper(itertools.cycle(data), batch_size)
chunks = [next(groups) for _ in range(how_many_groups)]
然后,块的结果是:

[(1, 2, 3, 4),
 (5, 1, 2, 3),
 (4, 5, 1, 2),
 (3, 4, 5, 1),
 (2, 3, 4, 5)]

因此,如果您确实需要这些列表,您必须将其转换为列表(
[list(next(groups))

您还可以使用
集合
模块中的
deque
,并在deque上进行一次旋转,如以下示例所示:

from collections import deque

def grouper(iterable, elements, rotations):
    if elements > len(iterable):
        return []

    b = deque(iterable)
    for _ in range(rotations):
        yield list(b)[:elements]
        b.rotate(1)


data = [1,2,3,4,5]
elements = 4
rotations = 5
final = list(grouper(data, elements, rotations))
print(final)
输出:

[[1, 2, 3, 4], [5, 1, 2, 3], [4, 5, 1, 2], [3, 4, 5, 1], [2, 3, 4, 5]]

您还可以使用
collections
模块中的
deque
,在deque上进行一次旋转,如以下示例所示:

from collections import deque

def grouper(iterable, elements, rotations):
    if elements > len(iterable):
        return []

    b = deque(iterable)
    for _ in range(rotations):
        yield list(b)[:elements]
        b.rotate(1)


data = [1,2,3,4,5]
elements = 4
rotations = 5
final = list(grouper(data, elements, rotations))
print(final)
输出:

[[1, 2, 3, 4], [5, 1, 2, 3], [4, 5, 1, 2], [3, 4, 5, 1], [2, 3, 4, 5]]

这可能比我的答案更有效!我应该更多地接触德克斯。你的回答也很好。我刚刚添加了另一种方法来实现这个技巧。解决OP问题的第一个也是最快捷的方法是使用
itertools.cycle()
。使用自定义方法的
deque
也可以实现同样的效果。@AdamSmith对我来说
it.cycle()
方法的速度快了几个数量级。创建一个完整的列表,然后进行切片是相对昂贵的。也许
islice
可以改进它。@AChampion,是的,如果你有任何建议,请告诉我,我会测试它们,我会修改我当前的答案。我也可以做一个基准。谢谢你的评论。另外,你假设你只需要
旋转(1)
旋转(-elements)
可能会更一般,例如,如果
数据=[1,2,3,4,5,6]
你会期望
[1,2,3,4],[5,6,1,2],…
,而不是
[1,2,3,4],[6,1,2,3],
这可能比我的答案更有效!我应该更多地接触德克斯。你的回答也很好。我刚刚添加了另一种方法来实现这个技巧。解决OP问题的第一个也是最快捷的方法是使用
itertools.cycle()
。使用自定义方法的
deque
也可以实现同样的效果。@AdamSmith对我来说
it.cycle()
方法的速度快了几个数量级。创建一个完整的列表,然后进行切片是相对昂贵的。也许
islice
可以改进它。@AChampion,是的,如果你有任何建议,请告诉我,我会测试它们,我会修改我当前的答案。我也可以做一个基准。谢谢你的评论。另外,你假设你只需要
旋转(1)
旋转(-elements)
可能会更一般,例如,如果
数据=[1,2,3,4,5,6]
你会期望
[1,2,3,4],[5,6,1,2],…
,而不是
[1,2,3,4],[6,1,2,3],
酷!甚至比python还要短!酷!甚至比python还要短!