Python列表推导创建多个列表

Hei*_*erg 16 python list-comprehension list

我想创建两个列表listOfAlistOfB存储的索引AB来自另一个列表秒.

s=['A','B','A','A','A','B','B']
Run Code Online (Sandbox Code Playgroud)

输出应该是两个列表

listOfA=[0,2,3,4]
listOfB=[1,5,6]
Run Code Online (Sandbox Code Playgroud)

我能用两个陈述来做到这一点.

listOfA=[idx for idx,x in enumerate(s) if x=='A']
listOfB=[idx for idx,x in enumerate(s) if x=='B']
Run Code Online (Sandbox Code Playgroud)

但是,我想仅使用列表推导仅在一次迭代中执行此操作.是否可以在一个声明中完成?就像是listOfA,listOfB=[--code goes here--]

Mar*_*ers 40

列表推导的定义是生成一个列表对象.你的2个列表对象的长度不同; 你必须使用副作用来达到你想要的效果.

不要在这里使用列表推导.只需使用普通循环:

listOfA, listOfB = [], []

for idx, x in enumerate(s):
    target = listOfA if x == 'A' else listOfB
    target.append(idx)
Run Code Online (Sandbox Code Playgroud)

这使您只需执行一个循环; 这将击败任何两个列表推导,至少直到开发人员找到一种方法使列表推导构建列表的速度是具有单独list.append()调用的循环的两倍.

我想任何一天挑这个在嵌套列表理解仅仅是能够产生在同一行两个列表.正如Python禅宗所说:

可读性很重要.

  • @Heisenberg:是的,因为Python可以完全用C来完成列表构建.没有讨厌的Python堆栈推送和弹出,没有`.append()`属性查找.我们可以稍微优化后者(在循环外使用`A,B = listOfA.append,listOfB.append`并重用它们),但堆栈调用仍然比C代码慢. (2认同)

Rem*_*ich 12

有点; 关键是生成一个2元素列表,然后解压缩:

listOfA, listOfB = [[idx for idx, x in enumerate(s) if x == c] for c in 'AB']
Run Code Online (Sandbox Code Playgroud)

也就是说,我认为这样做非常糟糕,显式循环更具可读性.

  • 这仍然循环两次,并且非常难以理解. (11认同)

Abh*_*jit 5

解决此问题的一个很好的方法是使用defaultdict.正如@Martin所说,列表理解不是生成两个列表的正确工具.使用defaultdict可以使用单次迭代创建隔离.此外,您的代码不会受到任何形式的限制.

>>> from collections import defaultdict
>>> s=['A','B','A','A','A','B','B']
>>> listOf = defaultdict(list)
>>> for idx, elem in enumerate(s):
    listOf[elem].append(idx)
>>> listOf['A'], listOf['B']
([0, 2, 3, 4], [1, 5, 6])
Run Code Online (Sandbox Code Playgroud)

  • 对于两个键,我会把钱放在我的条件语句上,打败你的`hash(elem)`调用. (2认同)