如何将具有多个字典的值列表的键解压缩到列表中而不会被覆盖?

时间:2019-05-02 04:46:32

标签: python list dictionary

我有一个词典列表:

data = [
    {'name': 'foo', 'scores': [2]},
    {'name': 'bar', 'scores': [4, 9, 3]},
    {'name': 'baz', 'scores': [6, 1]}
]

我想创建一个新列表,每个单独的score都这样分开:

list = [
    {'name': 'foo', 'scores': [2], 'score': 2},
    {'name': 'bar', 'scores': [4, 9, 3], 'score': 4},
    {'name': 'bar', 'scores': [4, 9, 3], 'score': 9},
    {'name': 'bar', 'scores': [4, 9, 3], 'score': 3},
    {'name': 'baz', 'scores': [6, 1], 'score': 6},
    {'name': 'baz', 'scores': [6, 1], 'score': 1}
]

然后,我可以遍历每个row和每个score,以创建一个新字典:

for row in data:
    scores = row['scores']  # list of values
    for score in scores:
        new_row = row
        new_row['score'] = score
        print(new_row)

这给了我我想要的东西

{'name': 'foo', 'scores': [2], 'score': 2}
{'name': 'bar', 'scores': [4, 9, 3], 'score': 4}
{'name': 'bar', 'scores': [4, 9, 3], 'score': 9}
{'name': 'bar', 'scores': [4, 9, 3], 'score': 3}
{'name': 'baz', 'scores': [6, 1], 'score': 6}
{'name': 'baz', 'scores': [6, 1], 'score': 1}

但是,我很难将这些词典添加到列表中。当我使用append()函数将每个词典添加到新列表中时:

list = []

for row in data:
    scores = row['scores']  # list of values
    for score in scores:
        new_row = row
        new_row['score'] = score
        list.append(new_row)

    print(list)

似乎覆盖一些先前的项目:

[
{'name': 'foo', 'scores': [2], 'score': 2},
{'name': 'bar', 'scores': [4, 9, 3], 'score': 3},
{'name': 'bar', 'scores': [4, 9, 3], 'score': 3},
{'name': 'bar', 'scores': [4, 9, 3], 'score': 3},
{'name': 'baz', 'scores': [6, 1], 'score': 1},
{'name': 'baz', 'scores': [6, 1], 'score': 1}
]

这是怎么回事?为什么正确地打印行,但是在添加到列表时会覆盖以前的项目?我以为append()只是将新项目添加到列表的末尾而无需更改其他项目?

3 个答案:

答案 0 :(得分:4)

这里new_row总是引用当前的row对象,这对于该行对象中的每个分数都是相同的。您需要创建一个复制当前行的新对象。使用deepcopy软件包中的copy

from copy import deepcopy
for row in data:
    scores = row['scores']  # list of values
    for score in scores:
        new_row = deepcopy(row)
        ...

答案 1 :(得分:4)

如何通过简单的列表理解就可以在一个步骤中实现所有这些目标:


                        innerhtml +="<div class='ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix'><span class='ui-dialog-title' id='ui-id-1'>Audio Comparison</span><a class='ui-dialog-titlebar-close ui-corner-all' role='button' href='#'><span class='ui-icon ui-icon-closethick'>close</span></a></div>";

说明/澄清

此列表理解完成了OP最终需要的工作。我们首先遍历字典列表In [269]: [{**d, **{'score': v}} for d in data for v in d['scores']] Out[269]: [{'name': 'foo', 'score': 2, 'scores': [2]}, {'name': 'bar', 'score': 4, 'scores': [4, 9, 3]}, {'name': 'bar', 'score': 9, 'scores': [4, 9, 3]}, {'name': 'bar', 'score': 3, 'scores': [4, 9, 3]}, {'name': 'baz', 'score': 6, 'scores': [6, 1]}, {'name': 'baz', 'score': 1, 'scores': [6, 1]}] 中的每个字典,并使用嵌套的data循环为当前字典v中的每个值scores

for

我们通过解压缩添加键for d in data for v in d['scores'] # order goes from left to right 和值score,然后我们也解压缩当前字典,因为OP也需要它。最后,我们使用v将这两者连接起来,这就是我们需要实现的目标。

使用{**d, **{'score': v}}{ }完成连接,因为我们从dict()d中解包了键和值;因此,一种替代方法是:

{'score': v}

有关字典解压缩示例的更多详细信息,请参阅peps/pep-0448/

答案 2 :(得分:0)

上面的答案很棒。谢谢! 在这里,我仅以一种简单的方式解释该错误的原因。 我添加了两个print():

for score in scores:
        print(row)
        new_row = row
        new_row['score'] = score
        list.append(new_row)
        print(list)

部分

......
{'name': 'bar', 'scores': [4, 9, 3]}
[{'name': 'foo', 'scores': [2], 'score': 2}, {'name': 'bar', 'scores': [4, 9, 3], 'score': 4}]
{'name': 'bar', 'scores': [4, 9, 3], 'score': 4}
[{'name': 'foo', 'scores': [2], 'score': 2}, {'name': 'bar', 'scores': [4, 9, 3], 'score': 9}, {'name': 'bar', 'scores': [4, 9, 3], 'score': 9}]
{'name': 'bar', 'scores': [4, 9, 3], 'score': 9}
[{'name': 'foo', 'scores': [2], 'score': 2}, {'name': 'bar', 'scores': [4, 9, 3], 'score': 3}, {'name': 'bar', 'scores': [4, 9, 3], 'score': 3}, {'name': 'bar', 'scores': [4, 9, 3], 'score': 3}]
......

所以现在我们可以看到new_row = row何时引用相同的对象。当new_row更改时,行也会更改。列表结果是每个scores的最后一个循环的结果。