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

问题描述 投票:0回答:3

从这些列表中,

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

我想我需要使用地图和邮政编码,所以我尝试了,

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

但这给出了

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

我认为问题是

lst2
是一个列表列表,但我只是不知道如何继续。

python dictionary lambda
3个回答
2
投票

使用理解:

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

由于存在嵌套循环,因此您需要一些东西来扩展第二个列表。简单:)


如果你更喜欢聪明而不是简单,还有另一种方法:

collections.ChainMap( *itertools.starmap( dict.fromkeys, zip(lst2, lst1)))

其工作方式是,

zip(lst2, lst1)
的每个元素都是一个元组,其中键列表作为第一个值,并将所有这些键分配给第二个值。这正是
dict.fromkeys

所期望的格式
>>> it = zip(lst2, lst1)
>>> x = next(it)
>>> x
([1, 2], 'a')
>>> dict.fromkeys(*x)
{1: 'a', 2: 'a'}

因此我们可以使用

itertools.starmap
将其应用于 zip 的每个元素,这为我们提供了部分字典的列表:

>>> list(itertools.starmap(dict.fromkeys, zip(lst2, lst1)))
[{1: 'a', 2: 'a'}, {3: 'b', 4: 'b', 5: 'b'}, {6: 'c', 7: 'c'}]

最后,我们将部分字典序列传递给

collections.ChainMap
,它本身可以用作字典,但如果您确实需要将其折叠为单个字典,则可以将其传递给
dict
构造函数:

>>> dict(collections.ChainMap(*itertools.starmap(dict.fromkeys, zip(lst2, lst1))))
{6: 'c', 7: 'c', 3: 'b', 4: 'b', 5: 'b', 1: 'a', 2: 'a'}

1
投票

编辑:

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

(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.starmap
dict.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'}

0
投票

为了好玩,只是一个具有字典理解的变体(类似于@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'}
© www.soinside.com 2019 - 2024. All rights reserved.