如何枚举具有两个“ for”的列表理解?

时间:2018-07-12 11:17:43

标签: python list-comprehension enumerate

我正在尝试

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时,我无法弄清楚如何做到这一点。我也找不到以前发布的这个问题。

3 个答案:

答案 0 :(得分:10)

您要在两个列表上创建一个Cartesian product,所以请使用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)

答案 1 :(得分:6)

您可以在配对序列上使用枚举。

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

答案 2 :(得分:2)

对于简单的嵌套循环,请按照@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]