如何从具有不同长度列表的字典中创建词典列表

时间:2019-09-09 09:04:37

标签: python dictionary list-comprehension itertools

我想创建一个字典列表,每个列表中的索引元素相同。

我有这本字典:

//Generate GD image from raw string.
if (!$source = @imagecreatefromstring($parsedData[4])){
    $message = 'Save Image: Ko. Img path: "' . $imgFullPath . '". Error details: ' . error_get_last()['message'];
    $this->logger->error($message);
}else {
    //Save GD image on disk
    imagejpeg($source, $imgFullPath);

    //Clean resources.
    imagedestroy($source);

    $message = 'Save Image: Ok. Image saved successfully on path: "' . $imgFullPath . '"...';
    $this->logger->info($message);
    $this->io->writeln($message);

所需的输出是:

d = {'name': ['bob', 'john', 'harry', 'mary'], 
     'age': [13, 19, 23], 
     'height': [164, 188], 
     'job': ['programmer']}

我尝试过这样的事情:

d2 = [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, 
      {'name': 'john', 'age': 19, 'height': 188}, 
      {'name': 'harry', 'age': 23},
      {'name': 'mary'}]

但是我的输出是:

d2 = [dict(zip(d, t)) for t in zip(*d.values())]

我认为这是因为列表的长度不同。

5 个答案:

答案 0 :(得分:23)

您可以使用itertools.zip_longest并过滤掉None值:

from itertools import zip_longest

[{x: y for x, y in zip(d, t) if y is not None} for t in zip_longest(*d.values())]
# [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, 
#  {'name': 'john', 'age': 19, 'height': 188}, 
#  {'name': 'harry', 'age': 23}, 
#  {'name': 'mary'}]

答案 1 :(得分:12)

您可以在此处使用zip_longest

from itertools import zip_longest

keys = d.keys()

d2 = [
    {k: v for k, v in zip(keys, vs) if v is not None}
    for vs in zip_longest(*d.values())
]

如果这些值也可以是None,我们可以使用一个虚拟值来规避它:

from itertools import zip_longest

keys = d.keys()
dummy = object()

d2 = [
    {k: v for k, v in zip(keys, vs) if v is not dummy}
    for vs in zip_longest(*d.values(), fillvalue=dummy)
]

这里,虚拟对象是一个对象,我们确定它不是d中项目的一部分(因为我们在构造d之后构造了它)。通过使用is比较,我们可以知道该值是否为“填充值”。

锡将给我们:

>>> d2
[{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, {'name': 'john', 'age': 19, 'height': 188}, {'name': 'harry', 'age': 23}, {'name': 'mary'}]

答案 2 :(得分:4)

这是另一种方法:

d = {'name': ['bob', 'john', 'harry', 'mary'], 'age': [13, 19, 23], 'height': [164, 188], 'job': ['programmer']}
m = max(map(len, d.values()))
d1 = {k : (v if len(v)==m else v+['']*(m-len(v))) for k,v in d.items()}
d2 = [{k:v for k,v in zip(d, t) if v} for t in zip(*d1.values())]
print(d2)

输出

[{'height': 164, 'age': 13, 'job': 'programmer', 'name': 'bob'}, {'height': 188, 'age': 19, 'name': 'john'}, {'age': 23, 'name': 'harry'}, {'name': 'mary'}]

答案 3 :(得分:4)

一个简单的解决方案,不使用zip_longest作记录:

d = {'name': ['bob', 'john', 'harry', 'mary'], 'age': [13, 19, 23], 'height': [164, 188], 'job': ['programmer']}

recordset = [{k: v[i] for k, v in d.items() if i < len(v)} for i in range(max([len(l) for l in d.values()]))]

print(recordset)  # >> [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, 
                        {'name': 'john', 'age': 19, 'height': 188}, 
                        {'name': 'harry', 'age': 23}, 
                        {'name': 'mary'}]

答案 4 :(得分:-1)

只需保留所有内容并添加以下导入语句:

从itertools导入zip_longest作为zip