如何以惯用方式批量处理序列的元素?
例如,对于序列“abcdef”和批量大小为2,我想做类似以下的事情:
for x, y in "abcdef":
print "%s%s\n" % (x, y)
ab
cd
ef
当然,这不起作用,因为它期望列表中的单个元素本身包含2个元素。
一个好的,简短的,干净的,pythonic的方法来处理批处理中列表的下n个元素,或者来自更大字符串的长度为n的子字符串(两个类似的问题)?
答案 0 :(得分:46)
生成器功能很整洁:
def batch_gen(data, batch_size):
for i in range(0, len(data), batch_size):
yield data[i:i+batch_size]
使用示例:
a = "abcdef"
for i in batch_gen(a, 2): print i
打印:
ab
cd
ef
答案 1 :(得分:13)
我有一种替代方法,适用于没有已知长度的迭代。
def groupsgen(seq, size):
it = iter(seq)
while True:
values = ()
for n in xrange(size):
values += (it.next(),)
yield values
它通过迭代大小组中的序列(或其他迭代器),收集元组中的值来工作。在每个组的末尾,它产生元组。
当迭代器用完值时,它会产生一个StopIteration异常,然后向上传播,表明groupsgen超出了值。
它假定值以大小集合(2,3组等)。如果没有,剩下的任何值都将被丢弃。
答案 2 :(得分:10)
不要忘记zip()函数:
a = 'abcdef'
for x,y in zip(a[::2], a[1::2]):
print '%s%s' % (x,y)
答案 3 :(得分:9)
我相信有人会想出更多“Pythonic”但是如何:
for y in range(0, len(x), 2):
print "%s%s" % (x[y], x[y+1])
请注意,这只有在您知道len(x) % 2 == 0;
答案 4 :(得分:6)
然后总是documentation。
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
try:
b.next()
except StopIteration:
pass
return izip(a, b)
def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
注意:当给定字符串序列作为输入时,这些产生元组而不是子串。
答案 5 :(得分:6)
但更通用的方式(受this answer启发):
for i in zip(*(seq[i::size] for i in range(size))):
print(i) # tuple of individual values
答案 6 :(得分:4)
>>> a = "abcdef"
>>> size = 2
>>> [a[x:x+size] for x in range(0, len(a), size)]
['ab', 'cd', 'ef']
..或者,不是列表理解:
a = "abcdef"
size = 2
output = []
for x in range(0, len(a), size):
output.append(a[x:x+size])
或者,作为一个生成器,如果多次使用它会是最好的(对于一次性使用的东西,列表理解可能是“最好的”):
def chunker(thelist, segsize):
for x in range(0, len(thelist), segsize):
yield thelist[x:x+segsize]
..它的用法:
>>> for seg in chunker(a, 2):
... print seg
...
ab
cd
ef
答案 7 :(得分:3)
您可以创建以下生成器
def chunks(seq, size):
a = range(0, len(seq), size)
b = range(size, len(seq) + 1, size)
for i, j in zip(a, b):
yield seq[i:j]
并像这样使用它:
for i in chunks('abcdef', 2):
print(i)
答案 8 :(得分:2)
来自docs of more_itertools:more_itertools.chunked()
more_itertools.chunked(iterable, n)
将iterable分解为给定长度的列表:
>>> list(chunked([1, 2, 3, 4, 5, 6, 7], 3))
[[1, 2, 3], [4, 5, 6], [7]]
如果iterable的长度不能被n整除,则最后返回的列表会更短。
答案 9 :(得分:1)
s = 'abcdefgh'
for e in (s[i:i+2] for i in range(0,len(s),2)):
print(e)
答案 10 :(得分:1)
itertools doc有一个配方:
from itertools import izip_longest
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 izip_longest(fillvalue=fillvalue, *args)
用法:
>>> l = [1,2,3,4,5,6,7,8,9]
>>> [z for z in grouper(l, 3)]
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]
答案 11 :(得分:1)
从this answer改用Python 3:
def groupsgen(seq, size):
it = iter(seq)
iterating = True
while iterating:
values = ()
try:
for n in range(size):
values += (next(it),)
except StopIteration:
iterating = False
if not len(values):
return None
yield values
如果值不能被size
整除,它将安全终止并且不会丢弃值。
答案 12 :(得分:0)
itertools怎么样?
from itertools import islice, groupby
def chunks_islice(seq, size):
while True:
aux = list(islice(seq, 0, size))
if not aux: break
yield "".join(aux)
def chunks_groupby(seq, size):
for k, chunk in groupby(enumerate(seq), lambda x: x[0] / size):
yield "".join([i[1] for i in chunk])
答案 13 :(得分:0)
一种解决方案,虽然我挑战某人做得更好; - )
a = 'abcdef'
b = [[a[i-1], a[i]] for i in range(1, len(a), 2)]
for x, y in b:
print "%s%s\n" % (x, y)
答案 14 :(得分:0)
除了两个答案外,我在批处理上看到了很多过早的实现,并且下标(这对所有迭代器都不起作用)。因此我提出了这个选择:
def iter_x_and_n(iterable, x, n):
yield x
try:
for _ in range(n):
yield next(iterable)
except StopIteration:
pass
def batched(iterable, n):
if n<1: raise ValueError("Can not create batches of size %d, number must be strictly positive" % n)
iterable = iter(iterable)
try:
for x in iterable:
yield iter_x_and_n(iterable, x, n-1)
except StopIteration:
pass
对我而言,没有单线或几线解决方案(据我所知)。关键问题是外部生成器和内部生成器都需要正确处理StopIteration。如果剩下至少一个元素,外部生成器应该只产生一些东西。检查这个的直观方法是执行下一个(...)并捕获一个StopIteration。
答案 15 :(得分:0)
鉴于
from __future__ import print_function # python 2.x
seq = "abcdef"
n = 2
代码
while seq:
print("{}".format(seq[:n]), end="\n")
seq = seq[n:]
输出
ab
cd
ef
答案 16 :(得分:0)
这是一个解决方案,它产生一系列迭代器,每个迭代器迭代 n 个项目。
def groupiter(thing, n):
def countiter(nextthing, thingiter, n):
yield nextthing
for _ in range(n - 1):
yield next(thingiter)
thingiter = iter(thing)
while True:
try:
nextthing = next(thingiter)
except StopIteration:
return None
yield countiter(nextthing, thingiter, n)
我按如下方式使用它:
table = list(range(250))
for group in groupiter(table, 16):
print(', '.join('0x{:02X}'.format(x) for x in group))
请注意,它可以处理对象的长度,而不是 n 的倍数。