简体   繁体   English

如何将包含多个词典的值列表的键解压缩到列表而不覆盖?

[英]How to unpack keys with list of values to multiple dictionaries to a list without overwriting?

I have a list of dictionaries: 我有一个词典列表:

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

I want to create a new list which has each individual score separated out like this: 我想创建一个新列表,将每个单独的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}
]

I can then loop through each row , and each score , to create a new dictionary: 然后我可以循环遍历每一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)

Which gives me exactly what I want: 这给了我我想要的东西:

{'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}

However, I'm having trouble adding these dictionaries to a list. 但是,我在将这些词典添加到列表时遇到了问题。 When I use the append() function to add each dictionary to a new list: 当我使用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)

It seems to overwrite some of the previous items: 它似乎覆盖了以前的一些项目:

[
{'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}
]

What's going on here? 这里发生了什么? Why is it printing the rows correctly, but overwriting previous items when adding to a list? 为什么正确打印行,但在添加到列表时覆盖以前的项目? I thought append() simply adds new items to the end of a list without altering other items? 我以为append()只是在列表末尾添加新项而不改变其他项?

Here new_row always reference the current row object, that is the same for every score in this row object. 这里new_row总是引用当前row对象,对于此行对象中的每个分数都是相同的。 You need to create a new object copying the current row. 您需要创建一个复制当前行的新对象。 Use deepcopy from the copy package. copy包中使用deepcopy

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

How about a simple list comprehension, to achieve all these in a single step: 简单的列表理解如何,只需一步即可实现所有这些:

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]}]

Explanation/Clarification : 说明/澄清

This list comprehension does what OP finally needs. 这个列表理解做了OP最终需要的。 We start by iterating over each dictionary in our list of dictionaries data and for each value v in current dictionary's scores with this nested for loop, 我们首先迭代字典data列表中的每个字典,并使用此嵌套for循环对当前字典的scores每个值v进行迭代,

for d in data for v in d['scores']  # order goes from left to right

we add a key score and a value v by unpacking and then we also unpack the current dictionary since OP needs that as well. 我们通过解压缩添加一个关键score和一个值v ,然后我们也解压缩当前字典,因为OP也需要它。 At the end we concatenate both of these using {**d, **{'score': v}} and that's what we need to achieve. 最后,我们使用{**d, **{'score': v}}连接这两个,这就是我们需要实现的目标。

The concatenation is done using { } or dict() because we unpack the keys and values from both d and {'score': v} ; 使用{ }dict()完成连接,因为我们从d{'score': v}解包密钥和值; Thus, an alternative is: 因此,另一种选择是:

In [3]: [dict(**d, **{'score': v}) for d in data for v in d['scores']]
Out[3]: 
[{'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]}]

For more details on dictionary unpacking examples, please refer peps/pep-0448/ 有关字典解包示例的更多详细信息,请参阅peps / pep-0448 /

The answers above are great. 上面的答案很棒。 Thanks! 谢谢! Here I just explain the reason of the bug in a simple way. 在这里,我只是简单地解释bug的原因。 I added two print(): 我添加了两个print():

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

part of the results: 部分结果:

......
{'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}]
......

So now we can see when new_row = row , they refer to the same object. 所以现在我们可以看到new_row = row ,它们引用同一个对象。 When new_row changes, row also changes. 当new_row更改时,行也会更改。 The list result is the result of the last loop for each scores . 列表结果是每个scores的最后一个循环的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM