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还要短!