Python:在字典中查找具有唯一值的键?
我收到一个字典作为输入,并希望返回一个键列表,其中字典值在该字典的范围内是唯一的 我将举例说明。假设我的输入是字典a,构造如下:Python:在字典中查找具有唯一值的键?,python,dictionary,Python,Dictionary,我收到一个字典作为输入,并希望返回一个键列表,其中字典值在该字典的范围内是唯一的 我将举例说明。假设我的输入是字典a,构造如下: a = dict() a['cat'] = 1 a['fish'] = 1 a['dog'] = 2 # <-- unique a['bat'] = 3 a['aardvark'] = 3 a['snake'] = 4 # <-- unique a['wallaby'] = 5 a['badger'] =
a = dict()
a['cat'] = 1
a['fish'] = 1
a['dog'] = 2 # <-- unique
a['bat'] = 3
a['aardvark'] = 3
a['snake'] = 4 # <-- unique
a['wallaby'] = 5
a['badger'] = 5
a=dict()
a['cat']=1
a[“鱼”]=1
注意,这实际上是一种蛮力:
l = a.values()
b = [x for x in a if l.count(a[x]) == 1]
您可以这样做(只需计算每个值的出现次数):
def唯一(a):
从集合导入defaultdict
count=defaultdict(lambda:0)
对于a.iteritems()中的k,v:
计数[v]+=1
对于v,c在计数中。iteritems():
如果c我认为dict太大的有效方法是
countMap = {}
for v in a.itervalues():
countMap[v] = countMap.get(v,0) + 1
uni = [ k for k, v in a.iteritems() if countMap[v] == 1]
使用嵌套列表理解
print [v[0] for v in
dict([(v, [k for k in a.keys() if a[k] == v])
for v in set(a.values())]).values()
if len(v) == 1]
这是另一个变体
>>> import collections
>>> inverse= collections.defaultdict(list)
>>> for k,v in a.items():
... inverse[v].append(k)
...
>>> [ v[0] for v in inverse.values() if len(v) == 1 ]
['dog', 'snake']
我倾向于此,因为反转字典是一种常见的设计模式。这里有一个解决方案,只需要遍历dict一次:
def unique_values(d):
seen = {} # dict (value, key)
result = set() # keys with unique values
for k,v in d.iteritems():
if v in seen:
result.discard(seen[v])
else:
seen[v] = k
result.add(k)
return list(result)
更详细一点,但只需要通过一次:
revDict = {}
for k, v in a.iteritems():
if v in revDict:
revDict[v] = None
else:
revDict[v] = k
[ x for x in revDict.itervalues() if x != None ]
(我希望它能工作,因为我不能在这里测试它)子类化怎么样
class UniqueValuesDict(dict):
def __init__(self, *args):
dict.__init__(self, *args)
self._inverse = {}
def __setitem__(self, key, value):
if value in self.values():
if value in self._inverse:
del self._inverse[value]
else:
self._inverse[value] = key
dict.__setitem__(self, key, value)
def unique_values(self):
return self._inverse.values()
a = UniqueValuesDict()
a['cat'] = 1
a['fish'] = 1
a[None] = 1
a['duck'] = 1
a['dog'] = 2 # <-- unique
a['bat'] = 3
a['aardvark'] = 3
a['snake'] = 4 # <-- unique
a['wallaby'] = 5
a['badger'] = 5
assert a.unique_values() == ['dog', 'snake']
类唯一值dict(dict):
定义初始化(self,*args):
dict.uuu init_uuu(self,*args)
self._倒数={}
定义设置项(自身、键、值):
如果self.values()中的值为:
如果值为自反:
del self.\u逆[值]
其他:
self.\u逆[值]=键
dict.\uuuuu setitem\uuuuuuuu(自身、键、值)
def唯一_值(自身):
返回self.\u inverse.values()
a=唯一值DICT()
a['cat']=1
a[“鱼”]=1
a[无]=1
a['duck']=1
a['dog']=2#它不会输出['dog','snake']l.count('dog')不是零吗?l在我的系统上是[3,3,2,1,4,5,1,5]。好的,我看到cobbal已经更正了代码。谢谢。这会产生值(2,4),而它应该产生键('dog','snake')。我发现defaultdict(int)
比defaultdict(lambda:0)
更清晰。因为几乎任何其他类型的默认dict都只会使用类型名称。如果一个值出现3次,您将尝试从结果中删除一个不存在的元素。。。文档说“删除(elem)”从集合中删除元素elem。如果元素不包含在集合中,则引发KeyError。“”没错!我已更正为使用discard()。您希望最后一行中的[v[0]代表k,v…]按请求获取['dog','snake'。(1)使用.iterms()代替.items(),而不是.items()。(2) 最后一行不必要地提取密钥;如果len(v)=1,则应为[v[0]。
(3)在任何情况下,构建整个反向dict都是多余的。如果其中一个字典键为None,则不起作用。例如,如果a为{None:1},则输出应为[None],但上述代码将生成[]。另外:x不是None
比x!=None
更可取。感谢您的评论!您完全正确。在实践中,很少使用None…但即使这样,也可以创建一些DummyObject:“Dummy=object()”不要使用None。我不认为以这种方式使用列表理解是一种胜利。对我来说,这只会使解决方案更难理解(没有双关语)。可读性是关键,这个解决方案在我看来不是那么可读。Rax要求“一种简洁的Python方法来完成工作”,而不是“显而易见”一个其他琐碎问题的解决方案。(1)在a
中使用k而不是在a.keys()中使用k
(2)使用whater.itervalues()
而不是whater.values()
(3)dict(yadda-yadda)部分正在低效地构建a
的本已过度使用的逆函数(4)它既不整洁,也不是Python(ic | ian)…但这肯定不是显而易见的!(5)统计那些第一次尝试解决所谓的琐碎问题的人的数量。这个解决方案可以编辑(仅使用delete键!)以避免构建逆运算;仍然是O(N^2),尽管:打印[v[0]表示v in[[k表示k in a,如果[k]==v]表示v in set(a.values())]如果len(v)==1]
这具有内存占用较小的优点,但最终会执行O(N)每次设置一个项目时都要进行搜索,因此它可能比字典制表法慢得多。此外,我认为你可以使用一个集合来代替dict。另一个问题:OP没有限制dict的内容是如何获得的。因此,人们会期望dela['bat'];print a.unique_values()
将导致输出中出现aardvark
,但遗憾的是,它没有出现,而修复该问题将需要更多的卷积和双下划线:-(使用集合会更美观。defaultdict(int),是的,但我会留下它,这样人们就会知道我们在没有defaultdicts@Ryan:True,但是lambda:0
比int
…更明确。在defaultdict到达[2.5]之前,知道int()产生0的人数[自2.2以来]而不是一个例外是revDict = {}
for k, v in a.iteritems():
if v in revDict:
revDict[v] = None
else:
revDict[v] = k
[ x for x in revDict.itervalues() if x != None ]
class UniqueValuesDict(dict):
def __init__(self, *args):
dict.__init__(self, *args)
self._inverse = {}
def __setitem__(self, key, value):
if value in self.values():
if value in self._inverse:
del self._inverse[value]
else:
self._inverse[value] = key
dict.__setitem__(self, key, value)
def unique_values(self):
return self._inverse.values()
a = UniqueValuesDict()
a['cat'] = 1
a['fish'] = 1
a[None] = 1
a['duck'] = 1
a['dog'] = 2 # <-- unique
a['bat'] = 3
a['aardvark'] = 3
a['snake'] = 4 # <-- unique
a['wallaby'] = 5
a['badger'] = 5
assert a.unique_values() == ['dog', 'snake']