Python 如何变换子序列?
假设我有一个函数,它接受一个生成器并生成一个新的生成器。例如,Python 如何变换子序列?,python,iterator,generator,Python,Iterator,Generator,假设我有一个函数,它接受一个生成器并生成一个新的生成器。例如,pair(gen)将序列1,2,3,4,转换为(1,2)、(3,4),… 现在我想取一个序列的生成器,将转换应用于它的子序列,同时保持其他元素不变。例如,如果gen生成序列1,2,3,4,5,并且我想在偶数元素上运行pair,那么with偶数(gen,pair)将生成1,3,(2,4),5,。它应该知道需要多少元素pair,也不应该缓存接收到的所有奇数,直到pair生成。它应该从主序列中获取下一项,如果是奇数,则产生它,如果是偶数,则
pair(gen)
将序列1,2,3,4,
转换为(1,2)、(3,4),…
现在我想取一个序列的生成器,将转换应用于它的子序列,同时保持其他元素不变。例如,如果gen
生成序列1,2,3,4,5,
并且我想在偶数元素上运行pair
,那么with偶数(gen,pair)
将生成1,3,(2,4),5,
。它应该知道需要多少元素pair
,也不应该缓存接收到的所有奇数,直到pair生成。它应该从主序列中获取下一项,如果是奇数,则产生它,如果是偶数,则将它馈送到变压器并重复
是否可以使用偶数定义?
如果对定义为
def pair(gen):
prev = None
for x in gen:
if prev:
yield (prev, x)
prev = None
else:
prev = x
那么一个带偶数运行对(gen)
,相当于带偶数(gen,pair)
,定义为
def withEvenRunPair(gen):
prev = None
for x in gen:
if x % 2 == 1:
yield x
else:
if prev:
yield (prev, x)
prev = None
else:
prev = x
然而,用偶数定义泛型似乎更难。我想你可以这样做:
from itertools import islice, izip, izip_longest, tee
def grouper(iterable, n, fillvalue=None):
# https://docs.python.org/2/library/itertools.html#recipes
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
def withEvenRunPair(gen):
it1, it2 = tee(gen)
odd = islice(it1, 0, None, 2)
even = islice(it2, 1, None, 2)
for a, b in izip_longest(grouper(odd, 2), grouper(even, 2)):
yield a
yield b
gen = (x for x in xrange(1, 13))
for x in withEvenRunPair(gen):
print x
输出:
(1, 3)
(2, 4)
(5, 7)
(6, 8)
(9, 11)
(10, 12)
你是说类似的东西吗
def pair(sequence, selector=bool, fill=None, error_on_fill=False):
sentinel = object()
previous = sentinel
for item in sequence:
if not selector(item):
yield item
continue
if previous is not sentinel:
yield previous, item
previous = sentinel
else:
previous = item
if previous is not sentinel:
if error_on_fill:
raise ValueError("Final selected item missing a paired valued")
yield previous, fill
result = list(pair(range(10), selector=(lambda x: x % 2 == 0)))
assert result == [1, (0, 2), 3, 5, (4, 6), 7, 9, (8, None)]
我终于找到了答案,尽管它需要对pair
进行一些更改和其他转换
停止计算并随后恢复计算的唯一方法是产生。因此,如果我们将input\u generator.next()
替换为某种类型的yield
,我们可以控制将值输入到转换的速度
首先我定义一个请求对象
class Get(object):
def isset(self):
return hasattr(self, 'value')
def set(self, x):
self.value = x
我现在将n=foo.next()
替换为
g = Get()
yield g
if not g.isset():
break
n = g.value
例如,我的问题中的对将变成
def pair(): #notice that there isn't an input generator any more
prev = None
while True: #there was a next() hidden inside 'for'
g = Get()
yield g
if not g.isset():
break
elif prev:
yield (prev, g.value)
prev = None
else:
prev = g.value
这种转换可以很容易地转化为适当的转换
def withGen(fn, gen):
for f in fn: #get the next request or result
if isinstance(f, Get):
f.set(gen.next()) #answer requests with gen.next()
else:
yield f #yield results
print [x for x in withGen(pair(), [1, 2, 3, 4].__iter__())]
#prints [(1, 2), (3, 4)]
最后,我们可以使用选择器定义
def withSelector(select, fn):
f = None #we need to remember the last unanswered request
while True:
if not f: #if last request has been answered...
f = fn.next() #get the next request, or the result
if isinstance(f, Get): #if it's a request...
g = Get()
yield g #ask for another input value
if not g.isset():
break
elif select(g.value): #if the values matches selector...
f.set(g.value) #feed it to transformation
f = None #and mark the request as answered
else:
yield g.value #otherwise just yield it
else: #if transformation yielded a result
yield f #yield it
f = None #and note that there is no request waiting
arr = range(1, 18)
print [x for x in withGen(withSelector(isEven, pair()), arr.__iter__())]
#prints [1, 3, (2, 4), 5, 7, (6, 8), 9, 11, (10, 12), 13, 15, (14, 16), 17]
我甚至可以给两个选择器排序。例如,如果我将add3
定义为yield
三个Get()
s,然后yield
它们的结果之和,我可以
print [x for x in withGen(withSelector(isOdd, add3()), withGen(withSelector(isEven, pair()), arr.__iter__()))]
#prints [(2, 4), 9, (6, 8), 27, (10, 12), (14, 16), 45]
我认为这里的问题是知道在哪里插入由pair
生成的结果。您可能会创建一个生成器,将偶数值提供给pair
,并在gen
上迭代,将值推送到输出或第一个生成器(因此将是一个队列),这取决于它们是奇数还是偶数。如果pair
已准备好生成输出,则可能与测试有关。不,我可以编写pair
和,甚至可以使用runpair
编写。我想要的是一个带有偶数
(或带有选择器
)的泛型,它将接受一个生成器和一个转换(对
只是一个示例),并将转换应用于生成的部分项。不,我可以使用偶数运行对编写对和,无论多么花哨。我想要的是一个通用的,带有偶数(或带有选择器),它将接受一个生成器和一个转换(配对只是一个示例),并将转换应用于部分生成的项。@KarolisJuodelė你能重新解释这个问题吗?也许可以提供更好的例子。我很难理解问题是什么。虽然有一个明显的问题。。。我想要的是用evenRunPair将拆分为两个函数,与even
和与pair
,这样我就可以将与even
应用于任何其他变换,如三元组(triple
(转换1,2,3),…)或One和Zero
(转换为1,2,3…->1,0,1,1,0,1,1,1,0)或我想到的任何东西。用evenRunones和zero编写似乎很容易,但分离函数似乎很难。