【问题标题】:How to interleave two iterators where x% of the samples come from one iterator, and (1-x)% come from the other如何交错两个迭代器,其中 x% 的样本来自一个迭代器,而 (1-x)% 来自另一个迭代器
【发布时间】:2020-11-10 07:39:25
【问题描述】:

说有两个迭代器:

def genA():
    while True:
        yield 1

def genB():
    while True:
        yield 2

gA = genA()
gB = genB()

根据this SO answer,它们可以使用itertools recipes均匀交错:

def cycle(iterable):
    # cycle('ABCD') --> A B C D A B C D A B C D ...
    saved = []
    for element in iterable:
        yield element
        saved.append(element)
    while saved:
        for element in saved:
              yield element

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    num_active = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while num_active:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            # Remove the iterator we just exhausted from the cycle.
            num_active -= 1
            nexts = cycle(islice(nexts, num_active))

aa = roundrobin(gA, gB)
next(aa)

所以next(aa) 每次都会移动迭代器输出,所以一堆next 调用将导致1, 2, 1, 2, 1, 2, 1 - 50% 将来自一个迭代器,另一个50% 将来自另一个.

我想知道我们如何对其进行编码,以便x% 来自一个迭代器,而(1-x)% 来自另一个迭代器。例如,75% 来自第一个迭代器,25% 来自另一个迭代器。

所以多次调用next(combinedIterator) 将导致如下结果:

1 1 1 2 1 1 1 2 1 1 1 2

出于我的目的,无论输出是像上面那样严格排序,还是随机的,输出由概率决定。

【问题讨论】:

    标签: python iterator


    【解决方案1】:

    如果您对确定性方法没问题(我从您的自我回答中了解到),您可以添加一个参数,即第一个迭代器的百分比,然后计算每个迭代器的“部分”。例如,如果您希望第一个迭代器中的 .75 - 这转换为:对于来自 iterator1 的每 三个 元素,从 @987654325 中产生 一个 元素@

    def interleave(itt1, itt2, itt1_per):
        itt1_frac, total = itt1_per.as_integer_ratio()
        itt2_frac = total - itt1_frac
        while True:
            for _ in range(itt1_frac):
                yield next(itt1)
            for _ in range(itt2_frac):
                yield next(itt2)
    
    newGen = interleave(gA, gB, .75)
    
    for _ in range(12):
        print(next(newGen), end=' ')
    

    这将打印:

    1 1 1 2 1 1 1 2 1 1 1 2 
    

    小心!这仅适用于“好”分数。例如:将此函数与.6 一起使用意味着对于来自iterator1 的每个5,404,319,552,844,595 元素,它将产生来自@987654332 的3,602,879,701,896,397 元素@

    克服这个问题的一种方法是将decimal.Decimalstring arguments一起使用:

    from decimal import Decimal
    
    def interleave(itt1, itt2, itt1_per):
        itt1_frac, total = Decimal(str(itt1_per)).as_integer_ratio()
        ...
    

    现在使用Decimal 意味着传递.6 会转化为更合理对于来自iterator1 的每三个 元素,yield 来自iterator2的两个元素。

    使用带有.6 作为参数的修改后的代码,将打印:

    1 1 1 2 2 1 1 1 2 2 1 1
    

    【讨论】:

      【解决方案2】:
      def genA():
          while True:
              yield 1
      
      def genB():
          while True:
              yield 2
      
      gA = genA()
      gB = genB()
      
      import random
      
      def xyz(itt1, itt2):
          while True:
              if random.random() < .25:
                  yield next(itt1)
              else:
                  yield next(itt2)
      
      newGen = xyz(gA, gB)
      
      next(newGen)
      

      这适用于均匀分布。我不会选择这个作为有人可能给出非概率性答案的答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-05
        • 2023-03-17
        • 2013-06-17
        • 2012-10-23
        • 2015-06-17
        • 2018-09-23
        • 2013-07-03
        相关资源
        最近更新 更多