Python字典如何通过键的值删除重复值?

3
一个字典
dic = {
 1: 'a', 
 2: 'a', 
 3: 'b', 
 4: 'a', 
 5: 'c', 
 6: 'd', 
 7: 'd', 
 8: 'a', 
 9: 'a'}

我希望删除重复的值,只保留一个键/值对,对于那些重复值的“键”选择,可以是最大值、最小值或随机选择其中一个重复项的键。

我不想使用k/v交换,因为它无法控制键的选择。

以值“a”为例。

 1: 'a', 
 2: 'a', 
 4: 'a', 
 8: 'a', 
 9: 'a'

最大的键将是{9: 'a'},最小的将是{1: 'a'},随机选择其中任何一个。

如果键是其他类型的可哈希值,例如字符串,则如何进行此选择?

有人能分享给我一个想法吗?

谢谢!


你能否反转它,使得键变成值,值变成键? - sas4740
OP确实说过“我不想使用k/v交换,因为它无法控制键的选择”——含糊不清,但我理解为值可以是列表、字典或其他不可接受作为键的对象。 - Alex Martelli
3个回答

5
您可以构建一个反向字典,其中值是初始字典的所有键的列表。使用这个反向字典,您可以进行最小值、最大值、随机值、交替最小和最大值等操作。
from collections import defaultdict

d = defaultdict(list)
for k,v in dic.iteritems():
    d[v].append(k)

print d
# {'a': [1, 2, 4, 8, 9], 'c': [5], 'b': [3], 'd': [6, 7]}

2
import itertools as it

newdic = {}
for v, grp in it.groupby(sorted((v, k) for k, v in dic.items)):
  newdic[min(k for _, k in grp)] = v

除了min之外,还有其他“选择”函数(当然,即使键是字符串,min也可以正常工作--在这种情况下,它会给你“字典序最小”的键)。

唯一需要注意的是,当与同一值对应的键可能是不可比较的(例如,复数或在Python 3中属于不同非全数字类型的对象)时,选择函数需要一些注意。但如果在min中使用key=就可以解决这个问题;-)。


谢谢Alex,我还在尝试找出如何按照你的方式随机选择重复键。 - K. C
@K.C.,random.choice(list(grp))[1] 是最简单的方法(当然,有更好的大O算法来实现这个目的,但是除非您的重复键组增长到每个键的成千上万的情况,否则没有部署它们的必要;-)。 - Alex Martelli

1

这将为您提供一个随机选择的唯一密钥:

In [29]: dic
Out[29]: {1: 'a', 2: 'a', 3: 'b', 4: 'a', 5: 'c', 6: 'd', 7: 'd', 8: 'a', 9: 'a'}

In [30]: dict((v,k) for k,v in dic.iteritems())
Out[30]: {'a': 9, 'b': 3, 'c': 5, 'd': 7}

In [31]: dict((v,k) for k,v in dict((v,k) for k,v in dic.iteritems()).iteritems())
Out[31]: {3: 'b', 5: 'c', 7: 'd', 9: 'a'}

1
你能解释一下为什么iteritem会返回随机值吗? - K. C
@Registered: Python的字典是无序的。因此,从dic.iteritems()中发射键值对的顺序是不确定的。我应该说“不确定”而不是“随机”。 - unutbu
@Registered:我没有注意到您要求不使用键值交换的方法。抱歉 - 这正是我上面所做的。我会让它保留供您阅读,然后在一天左右将其删除。 - unutbu
@~ubuntu,你不必删除它,因为这是一种我以前不知道的好方法。 - K. C

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