如何用两个“for”枚举列表理解?

How do I enumerate a list comprehension with two 'for's?

我正在努力

ls = [myfunc(a,b,i) for a in a_list for b in b_list]

但也将 i 传入 myfunc,这是一个从 0 开始并为每个新元素递增的索引。

例如:

a_list = 'abc'
b_list = 'def'

应该导致

ls = [myfunc('a','d',0),
      myfunc('a','e',1),
      myfunc('a','f',2),
      myfunc('b','d',3),
      myfunc('b','e',4),
      ...
      myfunc('c','f',8]

我知道我可以在正常情况下使用 enumerate(),即

ls = [myfunc(a,i) for a,i in enumerate(a_list)]

但是当有两个 for 时,我不知道如何干净利落地做到这一点。我也找不到之前发布的这个问题。

您正在创建一个 Cartesian product over two lists, so use itertools.product() 而不是双 for 循环。这为您提供了一个可迭代对象,您可以轻松地将 enumerate() 添加到:

from itertools import product

ls = [myfunc(a, b, i) for i, (a, b) in enumerate(product(a_list, b_list))]

对于不能使用 product() 的情况,您可以将多个循环放在生成器表达式中,然后向其中添加 enumerate()。假设您需要过滤 a_list:

的某些值
gen = (a, b for a in a_list if some_filter(a) for b in b_list)
ls = [myfunc(a, b, i) for i, (a, b) in enumerate(gen)]

另一种选择是添加一个单独的计数器; itertools.count() 给你一个计数器对象,它产生一个新值 next():

from itertools import count

counter = count()
ls = [myfunc(a, b, next(counter)) 
      for a in a_list if some_filter(a)
      for b in b_list]

毕竟,本质上 enumerate(iterable, start=0) 等同于 zip(itertools.count(start), iterable)

您可以对对的序列使用枚举。

ls = [myfunc(a,b,i) for (i,(a,b)) in
      enumerate((a,b) for a in a_list for b in b_list)]

对于简单的嵌套循环,按照@Martijn 的建议使用itertools.product()

如果表达式比较复杂你可以使用itertools.count:

i_gen = itertools.count()
ls = [myfunc(a, b, next(i_gen)) for a in a_list for b in b_list]