字典中嵌套列表的列表推导式

5

我有一个字典,其中每个值都是一个列表,就像这样:

dictA = {1:['a','b','c'],2:['d','e']}

很不幸,我无法更改这个结构来解决我的问题。

我想把所有列表的条目收集到一个单一的列表中,如下所示:

['a','b','c','d','e']

此外,我只想在if块中执行一次。由于我只想执行一次,所以不想将其存储到中间变量中,因此自然而然地使用列表推导式是正确的选择。但是怎么做呢?我的第一个猜测是:

[dictA[key] for key in dictA.keys()]

产量,
[['a','b','c'],['d','e']]

这并不起作用,因为

'a' in  [['a','b','c'],['d','e']]

产生`False`。我尝试过的所有其他方法都使用了某种非法语法。如何执行这样的推导?
5个回答

10

也要循环遍历返回的列表(直接循环遍历字典会同时得到键):

[value for key in dictA for value in dictA[key]]

或者更直接地使用dictA.itervalues()

[value for lst in dictA.itervalues() for value in lst]

列表推导式允许您嵌套循环;将上面的循环读作按相同顺序嵌套:

for lst in dictA.itervalues():
    for value in lst:
        # append value to the output list

或使用itertools.chain.from_iterable()

from itertools import chain

list(chain.from_iterable(dictA.itervalues()))

后者使用序列的序列,并让您像它们是一个大列表一样循环遍历它们。dictA.itervalues()会给您一个列表序列,而chain()将它们连接到一起供list()迭代并构建一个大列表。

如果你只是想在所有值中测试成员身份,那么你真正想要的是简单地遍历所有值,并测试你的值是否与每个值相匹配。 any()函数配合适当的生成器表达式就可以做到这一点:

any('a' in lst for lst in dictA.itervalues())

只要dictA中的任何一个值列举了'a',就会立即返回True,并且提前停止循环.itervalues()


当然,一旦我接受了你的回应,问题就变得更加复杂了。现在我需要从两个不同的字典中嵌套列表中提取所有名称。我可以使用zip()吗?因此,您的解决方案将是any('a' in lst for lst in zip(dictA.itervalues(),dictB.itervalues()) - wnnmaw
1
@wnnmaw: 再次使用 itertools.chain()any('a' in lst for lst in chain(dictA.itervalues(), dictB.itervalues())zip() 的功能完全不同。 - Martijn Pieters

2

如果你在检查成员资格(例如你的a in...示例),你可以将其重写为:

if any('a' in val for val in dictA.itervalues()):
    # do something

这样可以避免不必要的列表展平操作。

它在找到匹配项后也会立即短路(退出)。 - dansalmo
哎呀,我没看到你也提出了这种方法。我不是想像个小偷一样,抱歉! - Martijn Pieters
@Martijn 不用担心... :) (不过根据时间戳,我赢了 :P) - Jon Clements
那是因为我的最后一次编辑刚好超过了之前的宽限期。:-P 我也没有声称自己是第一个发帖的。 :-) - Martijn Pieters

0
在这种特定情况下,您可以使用嵌套推导式:
[value for key in dictA.keys() for value in dictA[key]]

但是一般来说,如果你已经知道如何将某个东西转换为嵌套列表,你可以使用chain.from_iterable来展开任何嵌套可迭代对象:

itertools.chain.from_iterable(dictA[key] for key in dictA.keys())

这将返回一个迭代器,而不是列表;如果您需要一个列表,只需显式地进行操作:

list(itertools.chain.from_iterable(dictA[key] for key in dictA.keys()))

顺便提一下,for key in dictA.keys()for key in dictA 做的事情是一样的,只不过在旧版本的Python中,它会浪费时间和内存来创建一个额外的键列表。正如文档所说,对于dictiteriterkeys相同。

因此,在以上所有版本中,最好只使用in dictA


@MartijnPieters:只是因为他在原始问题中提到了它;我打算添加一个解释,说明为什么它不是必需的。 - abarnert

0

在简单易懂的代码中,这可能会有所帮助。

ListA=[]
dictA = {1:['a','b','c'],2:['d','e']}
for keys in dictA:
    for values in dictA[keys]:
        ListA.append(values)

-1
你可以这样做...
output_list = []
[ output_list.extend(x) for x in {1:['a','b','c'],2:['d','e']}.values()]
输出的列表将会是 ['a', 'b', 'c', 'd', 'e']

5
不要为了副作用而使用列表推导式。在这里,你浪费了内存和 CPU 周期,因为你同时还在构建一个由 None 值组成的列表。 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接