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编写
似乎很容易,但分离函数似乎很难。