【问题标题】:How do I enumerate a list comprehension with two 'for's?如何用两个“for”枚举列表理解?
【发布时间】:2018-07-12 11:17:43
【问题描述】:

我正在努力

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)]

但是当有两个fors 时,我无法弄清楚如何干净利落地做到这一点。我也找不到以前发布的这个问题。

【问题讨论】:

  • 分两步完成。

标签: python list-comprehension enumerate


【解决方案1】:

您正在为两个列表创建 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)

【讨论】:

  • @tobias_k:那不是我。就是那边那个把纸袋套在头上的家伙。
  • @PetterFriberg:就是那个!他不断闯入我的房子!他们认为我看不到他们,但当我走过镜子时,我可以发现他们!
【解决方案2】:

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

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

【讨论】:

  • 如果你把不可读的行分成两个可读的行,我会给你一个赞成票(:编辑:这不是我的意思,但我猜它足够可读。
  • @Aran-Fey 当然。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2021-02-13
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 1970-01-01
    • 1970-01-01
    • 2022-08-08
    相关资源
    最近更新 更多