从一行中的两个列表创建字典

Create a dictionary from two lists in a one-liner

从这些列表中,

lst1 = ['a','b','c']
lst2 = [[1,2],[3,4,5],[6,7]]

我要创建:

{1: 'a', 3: 'b', 6: 'c', 2: 'a', 4: 'b', 7: 'c', 5: 'b'}

我可以使用 for 循环创建它:

d = {}
for l, nums in zip(lst1, lst2):
    for num in nums:
        d[num] = l

我想我需要使用 map 和 zip,所以我尝试了,

dict(map(lambda x: dict(x), zip(lst2,lst1)))

但这给出了

ValueError: dictionary update sequence element #1 has length 1; 2 is required.

我认为问题是 lst2 是一个列表列表,但我不知道如何继续。

使用理解:

d = {num:l for l, nums in zip(lst1, lst2) for num in nums}

因为有一个嵌套循环,你需要一些东西来扩展第二个列表,它可以用像 itertools.chain 这样的东西但是比仅仅写出循环要复杂得多,无论你是在理解或你现在正在做的。

编辑:

您的预期输出与循环产生的输出不同。如果您想在一个班轮中获得预期的输出(当然不包括进口),这是一种解决方案。

(i) 基于@mozway 使用 itertools.zip_longest 跨子列表创建元组 zip 对象的想法,使用 dict.fromkeys 方法从这些元组和 lst1 创建字典,

(ii) 使用 map 和字典理解,从 (i)

创建字典列表

(iii) 使用 functools.reduce,将列表展平为单个字典

from itertools import zip_longest
from functools import reduce
out = reduce(lambda d, x: {**d, **x}, map(lambda kv: {k:v for k,v in zip(*kv) if k is not None}, dict.fromkeys(zip_longest(*lst2), lst1).items()))

另一个解决方案:

from itertools import zip_longest, starmap
from functools import reduce
out = dict(reduce(lambda tp, x: tp+tuple(filter(None, x)), zip_longest(*map(dict.items, starmap(dict.fromkeys, zip(lst2, lst1))))))

输出:

{1: 'a', 3: 'b', 6: 'c', 2: 'a', 4: 'b', 7: 'c', 5: 'b'}

旧解决方案(如果顺序无关紧要):

正如您所说,问题在于 lst1 是一个列表,而 lst2 是一个列表列表。我们可以使用另一个 zip 从 lst1 创建子列表。然后使用 functools.reduce 来展平字典列表:

from functools import reduce
out = reduce(lambda d, x: {**d, **x}, 
             map(lambda x: dict(zip(x[0], [x[1]]*len(x[0]))), zip(lst2,lst1)))

或者使用@Tadhg 的优秀建议使用 itertools.starmapdict.fromkeys 方法,你也可以这样做:

from itertools import starmap
out = reduce(lambda d,x: {**d, **x}, starmap(dict.fromkeys, zip(lst2,lst1)))

或使用collections.ChainMap(更简单):

from collections import ChainMap
out = ChainMap(*starmap(dict.fromkeys, zip(lst2,lst1)))

输出:

{1: 'a', 2: 'a', 3: 'b', 4: 'b', 5: 'b', 6: 'c', 7: 'c'}

为了好玩,只是一个具有字典理解的变体(类似于@Tadhg 已经提出的),但保留子列表索引的顺序:

from itertools import zip_longest

out = {k: v for v, *keys in zip_longest(lst1, *lst2)
       for k in keys if k is not None}

输出:

{1: 'a', 3: 'a', 6: 'a', 2: 'b', 4: 'b', 7: 'b', 5: 'c'}