【问题标题】:Iterate on two lists and sync them迭代两个列表并同步它们
【发布时间】:2012-08-03 16:34:12
【问题描述】:

我需要通过以下方式迭代两个列表:

伪代码:

j=1
for i=1 to n:
   print a[i], b[j]
   while b[j+1] <= a[i]:
      j++
      print a[i], b[j]

例如:

a = [1 3 5 7]
b = [2 4 9] 

期望的输出:

1 2
3 2
5 2
5 4
7 4

你如何在python中干净利落地做到这一点?

【问题讨论】:

  • 这个问题对我来说似乎不完整,你能根据两个输入列表解释你的输出吗? 9 怎么了?
  • @Levon 9 没有出现在伪代码的输出中,正如我翻译的 Python 所示。

标签: python iteration


【解决方案1】:

您的伪代码几乎可以在 Python 中运行。一些可以满足您要求的工作代码是:

a = [1, 3, 5, 7]
b = [2, 4, 9] 
j = 0
for i in range(len(a)):
    print a[i], b[j]
    while j<len(b)-1 and b[j+1] <= a[i]:
        j += 1
        print a[i], b[j]

注意使它在 Python 中工作的一些更改:

  1. 声明列表时,项目之间需要逗号。
  2. 列表索引从 0 开始,因此 ij 都应该从那里开始。
  3. len(a) 返回a 的长度(在这种情况下为4),并迭代irange(len(a)) 为从0len(a)-1 的每个整数执行循环,这是@987654331 中的所有索引@。
  4. Python 不支持++ 操作,因此我们使用j +=1 代替。
  5. 我们必须避免使用b 的越界索引,因此我们测试以确保j 在递增之前会在界内。

通过遍历列表,可以使这段代码更加pythonic,如下所示:

a = [1, 3, 5, 7]
b = [2, 4, 9] 
j = 0
for element in a:
   print element, b[j]
   while j<len(b)-1 and b[j+1] <= element:
      j += 1
      print element, b[j]

一般来说,您可能不想只打印列表元素,因此对于更一般的用例,您可以创建一个generator,例如:

def sync_lists(a, b)
    if b:
        j = 0
        for element in a:
            yield (element, b[j])
            while j<len(b)-1 and b[j+1] <= element:
                j += 1
                yield (element, b[j])

然后你可以像以前一样打印它们

a = [1, 3, 5, 7]
b = [2, 4, 9]
for (e1, e2) in sync_lists(a, b):
    print e1, e2

【讨论】:

  • 是的,这似乎很不寻常,以至于直接翻译伪代码可能比一些带有nextitertools 的游戏更简单。不过,我可能会将这个迭代逻辑封装在一个生成器中,在我看来,这似乎是古怪迭代逻辑最 Pythonic 的“家”。
  • 我很好奇——你推荐使用enumerate,但看起来你不是在使用i。遍历列表不是更容易吗?
  • @SamMussmann 你是对的,我错过了。出于某种原因,我认为我仍然需要a 的索引。
【解决方案2】:

murgatroid99's answer 中的生成器代码可以通过使用 next() 而不是索引算法推广到任何可迭代对象(而不是仅序列):

def sync_list(a, b):
    b = iter(b)
    y, next_y = next(b), next(b)
    for x in a:
       yield x, y
       while next_y <= x:
          y, next_y = next_y, next(b)
          yield x, y

【讨论】:

  • 请注意,使用错误的数组,您可能会开始收到StopIteration 异常。我修改了我的代码以避免对应的IndexErrors。
  • @murgatroid99: StopIteration 由调用者处理,例如 for 循环。生成器中不需要对“错误”数组进行特殊处理。
  • @J.F.Sebastian 但 b 没有在 for 循环中迭代,所以调用者 sync_list。调用next 可以引发该异常,并且在循环中使用它并不能神奇地处理它。
  • @murgatroid99:如果 StopIteration 在生成器内部引发,这将终止生成器。我认为这是比打破不变量更合理的行为(这是你的新代码在b太短的情况下所做的)。
  • @murgatroid99:示例调用者是for e1, e2 in sync_lists(a, b):。它透明地处理StopIteration
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-11
  • 1970-01-01
  • 2022-06-27
  • 2018-02-10
  • 1970-01-01
  • 2014-02-01
相关资源
最近更新 更多