当字典中的值不唯一时,交换字典中的键和值

5

我想要在Python字典中将键(key)变为值(value),但原始字典中的值不唯一。

这是我的代码:

year_person = {2000: ‘Linda’, 2001: ‘Ron’, 2002: ‘Bruce’, 2003: ‘Linda’, 2004: ‘Bruce’, 2005 ‘Gary’, 2006: ‘Linda’}

This is what I want to change it to:

person_year = {‘Linda’: 2000, ‘Ron’: 2001, ‘Bruce’: 2002, ‘Linda’, 2003: ‘Bruce’, 2004 ‘Gary’, 2005: ‘Linda’: 2006}

当我尝试使用for循环进行转换时,每个人只能匹配到一个相应的对。

4
你不能那样做。每个键必须是唯一的。你可以为每个键创建一个值列表。 - alan
2
rel: https://dev59.com/iHRB5IYBdhLWcg3w3K8J - georg
4个回答

11

你也可以使用defaultdict来实现:

year_person = {2000: 'Linda', 2001: 'Ron', 2002: 'Bruce', 2003: 'Linda', 2004: 'Bruce', 2005: 'Gary', 2006: 'Linda'}

from collections import defaultdict
d = defaultdict(list)
for k, v in year_person.items():
    d[v].append(k)

print dict(d)
>>> {'Bruce': [2002, 2004], 'Linda': [2000, 2003, 2006], 'Ron': [2001], 'Gary': [2005]}

5
如果要使用defaultdict,则在实现该功能的函数返回时应将其转换为普通的dictdefaultdict 有一个令人讨厌的属性,即将未命中的属性转换为插入。也就是说,当您不想这样做时,它会导致错误。 - aaronasterling
是的,这就是为什么我在print语句中进行了转换。 - alan
5
那是一种并不十分透明的阐述潜在问题的方式。 - aaronasterling
你可以使用字典推导式来完成这个任务。它可能会对你有所帮助。 dict_two = {value:key for key,value in dict_one.iteritems()} - Syed Shahrukh Ali Gellani

7

为了提供一些其他选项和信息,可能与当前答案不同:

如果您确定您的值是唯一的,因此可以成为键,最简单的方法是使用字典推导式:

year_person = {2000: 'Linda', 2001: 'Ron', 2002: 'Bruce', 2003: 'Linda', 2004: 'Bruce', 2005: 'Gary', 2006: 'Linda'}
person_year = {key: value for (value, key) in year_person.items()}

当然,在你的情况下,它们并不是一样的,所以这种方法行不通(因为它仅返回找到的最后一个值):
person_year = {'Bruce': 2004, 'Linda': 2006, 'Ron': 2001, 'Gary': 2005}

我们可以使用字典推导式内嵌列表推导式来替代:

{key: [value for value, check_key in year_person.items() if check_key==key] for key in year_person.values()}

给我们:
{'Bruce': [2002, 2004], 'Linda': [2000, 2003, 2006], 'Ron': [2001], 'Gary': [2005]}

这种方法可以工作,但由于需要在每个条目上循环整个字典,因此效率不高。更好的解决方案是alan提供的defaultdict解决方案,只需要一个循环即可。


3
您想要实现的技术上不可行。字典的关键字不能重复,否则您将无法使用关键字唯一地索引一个字典。
但是,您可以创建一个(key,value)对的字典,其中value是具有相同key的所有项的列表。为了实现这一点,您可以按照以下方式进行操作:
>>> person_year={}
>>> [person_year.setdefault(v,[]).append(k) for (k,v) in year_person.iteritems()]
[None, None, None, None, None, None, None]
>>> person_year
{'Bruce': [2002, 2004], 'Linda': [2000, 2003, 2006], 'Ron': [2001], 'Gary': [2005]}
>>> 

请注意,如果您只对键值对感兴趣而不是字典本身,您可以按以下方式将其存储为元组列表。
>>> [(v,k) for k,v in year_person.iteritems()]
[('Linda', 2000), ('Ron', 2001), ('Bruce', 2002), ('Linda', 2003), ('Bruce', 2004), ('Gary', 2005), ('Linda', 2006)]
>>>

1
我会将这描述为不符合Python风格 - 列表推导式的设计目的是用于创建列表,而不是处理数据。在这种情况下,一个更清晰、更简洁的解决方案是使用Alan提供的defaultdict。另外值得注意的是,“iteritems()”仅存在于Python 3.x之前的版本中,在此之后,只需使用“items()”。 - Gareth Latty

2

在我看来,这里不需要使用defaultdict,而且用列表推导式实现会牺牲可读性(尽管通常情况下并非如此)。除非分析表明这真的是瓶颈,否则我会按以下方式实现:

def invert_to_lists(dct):
    inverted_dict = {}
    for key in dct:
        inverted_dict.setdefault(dct[key], []).append(key)
    return inverted_dict

defaultdict是一种更复杂的方式。在这种情况下,使用setdefault是可以接受的,因为它只需要输入一次。如果要导入并实例化一个defaultdict,则需要键入的内容比调用setdefault还要多。


那么问题出在哪里呢?为什么会被踩票? - aaronasterling

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