Python从一个键列表和一个值的列表列表中构建一个字典

4

所以我有一组键:

keys = ['id','name', 'date', 'size', 'actions']

我还有一个值的列表列表:

values=
    [
        ['1','John','23-04-2015','0','action1'],
        ['2','Jane','23-04-2015','1','action2']
    ]

我该如何建立一个字典,使得键与值匹配?
输出应为:
{
    'id':['1','2'],
    'name':['John','Jane'],
    'date':['23-04-2015','23-04-2015'],
    'size':['0','1'],
    'actions':['action1','action2']
}

编辑: 我尝试使用zip()和dict(),但只有当值的列表只有1个列表时才有效,例如values = [['1','John','23-04-2015','0','action1']]
for list in values:
    dic = dict(zip(keys,list))

我也考虑过用键初始化字典,然后自己构建值列表,但我觉得一定有更简单的方法来做到这一点。

dic = dict.fromkeys(keys)

for list in values:
    ids = list[0]
    names = list[1]
    dates = list[2]
    sizes = list[3]
    actions = list[4]

然后最终

dic['id'] = ids
dic['name'] = names
dic['date'] = dates
dic['size'] = sizes
dic['action'] = actions

这似乎很愚蠢,我在想有没有更好的方法来做。

你自己试过了吗? - sshashank124
我尝试使用zip()函数,但似乎无法得到我想要的结果。 - Andrew
1
请展示您已尝试的代码,这样我们才能帮助您。 - sshashank124
已编辑以显示我尝试过的内容 - Andrew
1个回答

9
>>> keys = ['id','name', 'date', 'size', 'actions']
>>> values = [['1','John','23-04-2015','0','action1'], ['2','Jane','23-04-2015','1','action2']]
>>> c = {x:list(y) for x,y in zip(keys, zip(*values))}
>>> c
{'id': ['1', '2'], 'size': ['0', '1'], 'actions': ['action1', 'action2'], 'date': ['23-04-2015', '23-04-2015'], 'name': ['John', 'Jane']}
>>> print(*(': '.join([item, ', '.join(c.get(item))]) for item in sorted(c, key=lambda x: keys.index(x))), sep='\n')
id: 1, 2
name: John, Jane
date: 23-04-2015, 23-04-2015
size: 0, 1
actions: action1, action2

这里使用了几个工具:

c 是通过字典推导式创建的。推导式是一种不同于初始化一个空可迭代对象并使用循环向其中添加元素的方式,而是将这些语法结构移动到周围的方法。

result = [2*num for num in range(10) if num%2]

等同于

result = []
for num in range(10):
    if num%2: # shorthand for "if num%2 results in non-zero", or "if num is not divisible by 2"
        result.append(2*num)

我们得到了[2, 6, 10, 14, 18]

zip()创建一个元组的生成器,其中每个元组的每个元素都是您传递给zip()的参数之一的相应元素。

>>> list(zip(['a','b'], ['c','d']))
[('a', 'c'), ('b', 'd')]

zip() 接受多个参数 - 如果您传递一个包含较小子列表的大列表,则结果会有所不同:

>>> list(zip([['a','b'], ['c','d']]))
[(['a', 'b'],), (['c', 'd'],)]

通常情况下,我们不需要的是一个包含子列表的大型列表,而这正是我们的values列表。我们希望将这些子列表使用zip()函数进行合并。这是使用*运算符的好时机。

*运算符代表了一个“展开”的可迭代对象。

>>> print(*[1,2,3])
1 2 3
>>> print(1, 2, 3)
1 2 3

它也被用于函数定义中:

>>> def func(*args):
...    return args
...
>>> func('a', 'b', [])
('a', 'b', [])

因此,为了创建字典,我们将值列表zip()在一起,然后将其与键一起zip()。然后我们遍历每个元组并从中创建一个字典,其中每个元组的第一个项是键,第二个项是值(作为list而不是tuple进行转换)。
要打印这个字典,我们可以制作一个大型循环结构,或者我们可以制作生成器(比像list这样的完整数据结构更快地组装和处理),并通过它们迭代,大量使用*来解包事物。请记住,在Python 3中,print可以接受多个参数,如上所示。
我们将首先对字典进行排序,使用每个元素在keys中的位置作为键。如果我们使用像key=len这样的东西,那么它会将每个元素发送到len()函数,并将返回的长度用作键。我们使用lambda来定义一个内联的、无名的函数,它接受一个参数x并返回xkeyslist中的索引。请注意,字典实际上并没有排序;我们只是设置它,以便我们可以根据排序顺序遍历它。
然后,我们可以遍历这个排序后的字典,并将其元素组装成可打印的字符串。在顶层,我们使用join()将一个键与其值分隔符': '连接起来。每个值都使用', '连接它的元素。请注意,如果元素不是字符串,我们必须将它们转换为字符串,以便join()正常工作。
>>> list(map(str, [1,2,3]))
['1', '2', '3']
>>> print(*map(str, [1,2,3]))
1 2 3

生成器使用yield返回每个连接的行,然后使用*运算符解包生成器,并将每个元素作为参数发送到print(),指定分隔符为'\n'(换行)而不是默认的' '(空格)。
如果你愿意,完全可以使用循环而非列表推导和*,然后在逻辑可用之后再将它们重新排列成这样的结构。大多数情况下并不特别必要。列表推导有时比等效循环执行速度稍快,通过实践你可能会更喜欢列表推导的语法。但一定要学习*运算符——它是定义函数的极其多才多艺的工具。还要了解**(通常称为“双星号”或“kwargs”),它将字典解包为关键字参数,也可以用于定义函数。

你能否详细解释一下正在发生的事情?特别是关于 * 的部分;我以前从未见过它被使用过。 - Andrew

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