如何制作一个有两个列表和列表索引的字典?



我有两个并行的数据列表,如:

genres = ["classic", "pop", "classic", "classic", "pop"]
plays = [500, 600, 150, 800, 2500]

我想要得到这个结果:

album = {"classic":{0:500, 2:150, 3:800}, "pop":{1:600, 4:2500}} # want to make

所以我试了这个代码:

album = dict.fromkeys(genres,dict())
# album = {'classic': {}, 'pop': {}}
for i in range(len(genres)):
for key,value in album.items():
if genres[i] == key:
album[key].update({i:plays[i]})

album的结果错误。它看起来像

{'classic': {0: 500, 1: 600, 2: 150, 3: 800, 4: 2500},
'pop': {0: 500, 1: 600, 2: 150, 3: 800, 4: 2500}}

也就是说,每个plays值都被添加到两个类型中,而不是只添加到与该数字对应的类型中。

为什么会出现这种情况?我该如何解决这个问题?

尝试用

替换album = dict.fromkeys(genres,dict())
album = {genre: {} for genre in genres}

您的dict.fromkeys不工作的原因记录在文档中:

fromkeys()是一个返回新字典的类方法。value默认为None。所有的值都只引用一个实例,所以value作为一个可变对象(如空列表)通常是没有意义的。若要获得不同的值,请使用字典推导式。

也就是说,当您编写album = dict.fromkeys(genres,dict())album['classic']album['pop']时,它们都是相同的对象。当您向其中一个添加新项时,它将应用于另一个(因为它们是相同的对象)。

或者,您可以使用defaultdictzip:

from collections import defaultdict
genres = ["classic", "pop", "classic", "classic", "pop"]
plays = [500, 600, 150, 800, 2500]
album = defaultdict(dict)
for i, (genre, play) in enumerate(zip(genres, plays)):
album[genre][i] = play
print(dict(album))
# {'classic': {0: 500, 2: 150, 3: 800}, 'pop': {1: 600, 4: 2500}}

dict(album)在大多数情况下是冗余的;你可以像使用字典一样使用album

使用说明:

In [1059]: d = {}
In [1060]: for c,i in enumerate(genres):
...:     if i in d:
...:         d[i].update({c:plays[c]})
...:     else:
...:         d[i] = {c:plays[c]}
...: 
In [1061]: d
Out[1061]: {'classic': {0: 500, 2: 150, 3: 800}, 'pop': {1: 600, 4: 2500}}

这里有两个问题:首先,for key,value in album.items():循环是冗余的,尽管这不会造成问题,因为字典有唯一的键-您将存储每个键-值对两次,但第二次只会替换第一次。

重要的问题是,在album = dict.fromkeys(genres,dict())之后,album中的两个值将是相同的字典。dict()在调用dict.fromkeys之前发生,并传入结果对象。dict.fromkeys()使用相同的对象作为每个键的值——它不复制

要解决这个问题,可以使用字典推导来创建字典:

album = {g: {} for g in genres}

这是一个类似于意外地跨子列表反映列表的列表更改的问题,不同的是,它不是列表的列表,而是带有字典值的字典,并且不是通过乘法创建有问题的数据,而是使用方法创建它。然而,底层逻辑是相同的,自然的解决方案也以相同的方式工作。

另一种方法是在album中只在第一次需要时创建键值对,首先检查它们是否存在。

另一种方法是使用自动按需创建的工具——例如,从标准库collections模块中创建defaultdict。这种方式看起来像:

from collections import defaultdict
# other code until we get to:
album = defaultdict(dict)
# whenever we try `album[k].update(v)`, if there is not already an
# `album[k]`, it will automatically create `album[k] = dict()` first
# - with a new dictionary, created just then.

@j1-lee回答正确,但如果您想避免使用defaultdict而使用原始字典,下面是代码。

genres = ["classic", "pop", "classic", "classic", "pop"]
plays = [500, 600, 150, 800, 2500]
all_genres_plays = zip(genres, plays)
album = {}
for index, single_genre_play in enumerate(all_genres_plays):
genre, play = single_genre_play
if genre not in album:
album[genre] = {}
album[genre][index] = play
print(album)

输出:

{'classic': {0: 500, 2: 150, 3: 800}, 'pop': {1: 600, 4: 2500}}

相关内容

  • 没有找到相关文章

最新更新