在字典中按值获取键
Posted
技术标签:
【中文标题】在字典中按值获取键【英文标题】:Get key by value in dictionary 【发布时间】:2022-01-15 17:32:09 【问题描述】:我做了一个函数,它会在 Dictionary
中查找年龄并显示匹配的名称:
dictionary = 'george' : 16, 'amber' : 19
search_age = raw_input("Provide age")
for age in dictionary.values():
if age == search_age:
name = dictionary[age]
print name
我知道如何比较和查找我只是不知道如何显示人名的年龄。此外,由于第 5 行,我收到了 KeyError
。我知道它不正确,但我不知道如何让它向后搜索。
【问题讨论】:
相关:Reverse / invert a dictionary mapping 你会根据字典中的定义找到一个单词吗?不。 您无法打开上锁的门。 (当然,除非你打破它) 【参考方案1】:mydict = 'george': 16, 'amber': 19
print mydict.keys()[mydict.values().index(16)] # Prints george
或者在 Python 3.x 中:
mydict = 'george': 16, 'amber': 19
print(list(mydict.keys())[list(mydict.values()).index(16)]) # Prints george
基本上,它将字典的值分隔在一个列表中,找到你所拥有的值的位置,并获取该位置的键。
更多关于 Python 3 中的 keys()
和 .values()
:How can I get list of values from dict?
【讨论】:
看起来不错,但它总是有效吗?我的意思是,list.keys()
和 list.values()
函数是否以相同的顺序生成项目?
是的,它们保证是一致的。此外,只要字典没有被修改,就保证不会通过迭代改变顺序。
这看起来是一个很好的解决方案,但是 index 只给出了一个正确的值,所以如果你有多个相等的值,那么它应该返回多个键对吗?
@ArtOfWarfare docs.python.org/3/library/stdtypes.html#dict-views, "如果键、值和项目视图被迭代而没有对字典进行干预修改,项目的顺序将直接对应。"
@sinekonata:它仍然在后台执行昂贵的循环;循环只是隐藏在 index
方法中。【参考方案2】:
没有。 dict
不适合以这种方式使用。
dictionary = 'george': 16, 'amber': 19
search_age = input("Provide age")
for name, age in dictionary.items(): # for name, age in dictionary.iteritems(): (for Python 2.x)
if age == search_age:
print(name)
【讨论】:
我不同意... agf 下面的回答更具建设性。一个完全合理的用例不是“意外的”(列表理解无论如何都适合这样的用例)。dict
可以在不同时间用于多个事物;当然,键和值具有明确的含义,但是 "dict
items with a given value" 是一个完全合理的请求。使用对列表的建议将丢弃一个项目是另一个项目的“定义”的上下文,例如在参数列表中...
我不同意这个答案。正如 Stênio Elson 在回答中所显示的那样,这是一种可能性这一事实并不意味着它不打算被这样使用。一点帮助都没有。
你会根据定义在字典中找到一个单词吗?没有。 @Tropicalrambler
虽然您有一点,单词字典的标准用法是使用 word = key 和 definition = value 搜索单词的定义,但今天的编程语言允许您在必要时按值搜索。如果您正在使用键:值对对象(将其称为字典、元组、任何语言的任何名称)。在python中,你仍然可以通过索引结构的值来找出对应的键。
@JossieCalderon 是的。我经常在谷歌上搜索我想要得到这个词的意思的描述。这本质上是根据定义在字典中查找一个单词。【参考方案3】:
如果你想要名字和年龄,你应该使用.items()
它给你键(key, value)
元组:
for name, age in mydict.items():
if age == search_age:
print name
您可以在 for
循环中将元组解压缩为两个单独的变量,然后匹配年龄。
如果您通常要按年龄查找,并且没有两个人的年龄相同,您还应该考虑反转字典:
16: 'george', 19: 'amber'
所以你可以通过这样做来查找年龄的名字
mydict[search_age]
我一直称它为mydict
而不是list
,因为list
是一个内置类型的名称,您不应该将该名称用于其他任何内容。
您甚至可以在一行中获取所有具有给定年龄的人的列表:
[name for name, age in mydict.items() if age == search_age]
或者如果每个年龄只有一个人:
next((name for name, age in mydict.items() if age == search_age), None)
如果没有那个年龄的人,它只会给你None
。
最后,如果 dict
很长并且您使用的是 Python 2,您应该考虑使用 .iteritems()
而不是 .items()
,就像 Cat Plus Plus 在他的回答中所做的那样,因为它不需要制作列表的副本。
【讨论】:
正确,但如果您要进行线性搜索,不妨将dict
替换为对列表。
除非您通常的操作是按名称查找年龄,在这种情况下,dict
是有意义的。
假设每个年龄只有一个人似乎很奇怪,而另一方面,每个人都有一个年龄是完全合乎逻辑的。
@Dannid 是的,但问题很容易概括。例如,您可以有一个带有唯一键及其相应唯一值的查找表。然后你可以对称地查找东西 value --> key
或 key --> value
【参考方案4】:
我认为指出哪些方法最快以及在什么情况下会很有趣:
这是我运行的一些测试(在 2012 MacBook Pro 上)
def method1(dict, search_age):
for name, age in dict.iteritems():
if age == search_age:
return name
def method2(dict, search_age):
return [name for name,age in dict.iteritems() if age == search_age]
def method3(dict, search_age):
return dict.keys()[dict.values().index(search_age)]
profile.run()
对每种方法的结果 100,000 次:
方法一:
>>> profile.run("for i in range(0,100000): method1(dict, 16)")
200004 function calls in 1.173 seconds
方法二:
>>> profile.run("for i in range(0,100000): method2(dict, 16)")
200004 function calls in 1.222 seconds
方法三:
>>> profile.run("for i in range(0,100000): method3(dict, 16)")
400004 function calls in 2.125 seconds
所以这表明对于一个小的 dict,方法 1 是最快的。这很可能是因为它返回第一个匹配项,而不是方法 2 之类的所有匹配项(请参阅下面的注释)。
有趣的是,对我有 2700 个条目的 dict 执行相同的测试,我得到完全不同的结果(这次运行 10,000 次):
方法一:
>>> profile.run("for i in range(0,10000): method1(UIC_CRS,'7088380')")
20004 function calls in 2.928 seconds
方法二:
>>> profile.run("for i in range(0,10000): method2(UIC_CRS,'7088380')")
20004 function calls in 3.872 seconds
方法三:
>>> profile.run("for i in range(0,10000): method3(UIC_CRS,'7088380')")
40004 function calls in 1.176 seconds
所以在这里,方法 3 要快得多。只是去显示你的 dict 的大小会影响你选择的方法。
注意事项:
方法 2 返回所有名的列表,而方法 1 和 3 仅返回第一个匹配项。 我没有考虑内存使用情况。我不确定方法 3 是否会创建 2 个额外的列表(keys()
和 values()
)并将它们存储在内存中。
【讨论】:
只是一个更新:似乎 dict.values() 和 dict.keys() 都返回引用原始 dict 对象的列表,因此方法 3 也是使用最少内存的方法(它只创建两个包装字典内容的薄列表对象,而其他创建迭代器项 我只是想自己对它进行基准测试,向下滚动,bam 你有它。谢谢!从技术上讲,正如您已经指出的那样,方法 2 的作用与 1 和 3 不同,因为它返回所有匹配项。很高兴看到例如结果返回下一个([..])。 @Martijn @Patrick,从 python 3.6 开始,dict_keys dict_values 不再具有索引属性,您需要先将其转换为列表,我猜这会占用内存(方法 3)。所以它最终像list(dict.keys())[list(dict.values()).index(search_age)]
@OrsirisdeJong dict.keys()
等是字典视图对象,并且在所有 Python 3 版本中都是如此,而不仅仅是从 3.6 开始。不要将它们变成列表,使用next((k for k, v in dict.items() if v == search_age), None)
查找匹配项。
@MartijnPieters 实际上,您的解决方案比列表占用更少的内存,并且很好地替换了方法 3。只是一件事,你在反转 k 和 v 时出错了。正确的版本应该是next((k for k, v in dict.items() if v == search_age), None)
。不管怎样,谢谢你的回答;)【参考方案5】:
单行版本:(i为旧字典,p为逆字典)
解释:i.keys()
和i.values()
分别返回两个列表,其中包含字典的键和值。 zip 函数能够将列表捆绑在一起以生成字典。
p = dict(zip(i.values(),i.keys()))
警告:这仅在值是可散列且唯一的情况下才有效。
【讨论】:
是的,这会起作用:***.com/questions/835092/… ...当没有重复值时。 美丽。写上面的评论,当然它只在没有重复值的情况下才有效,但是,启动这个线程的问题假设我们有一个一对一的函数,所以给定这个假设,这是最优雅的到目前为止的回应。 扩展可哈希值:如果您的值是列表/集合,请将它们转换为元组以使其工作(它们仍然需要是唯一的)。【参考方案6】:a = 'a':1,'b':2,'c':3
v:k for k, v in a.items()[1]
或更好
k:v for k, v in a.items() if v == 1
【讨论】:
如果有另一个键持有与 a 相同的值怎么办?可能是pythonic方式。但不是一个好主意。 好点,我添加了适用于非唯一值的解决方案【参考方案7】:key = next((k for k in my_dict if my_dict[k] == val), None)
【讨论】:
我也可以在同一行中添加“else”吗?对于我的值不在字典值中的情况lKey = [k for k, v in lDictionary.iteritems() if v == lValue][0] or 'else-key'
【参考方案8】:
我发现这个answer 非常有效,但对我来说不太容易阅读。
为了更清楚,您可以反转字典的键和值。这是使键值和值键,如 here 所示。
mydict = 'george':16,'amber':19
res = dict((v,k) for k,v in mydict.iteritems())
print(res[16]) # Prints george
或者对于 Python 3,(感谢 @kkgarg)
mydict = 'george':16,'amber':19
res = dict((v,k) for k,v in mydict.items())
print(res[16]) # Prints george
还有
print(res.get(16)) # Prints george
这与另一个answer基本相同。
【讨论】:
如果您有像'george':16,'amber':19,'jack':16
这样的重复值,这可能不起作用
即使有重复值,它确实只会返回一个值。
或者您可以在 Python 3 中执行此操作:[k for k, v in dictionary.items() if v == 16])
【参考方案9】:
试试这个单行来反转字典:
reversed_dictionary = dict(map(reversed, dictionary.items()))
【讨论】:
这对我的加密和解密程序非常有用,谢谢!【参考方案10】:如果您想通过值查找键,可以使用字典推导创建查找字典,然后使用它从值中查找键。
lookup = value: key for key, value in self.data
lookup[value]
【讨论】:
【参考方案11】:您可以使用dict.keys()
、dict.values()
和list.index()
方法获取密钥,请参见下面的代码示例:
names_dict = 'george':16,'amber':19
search_age = int(raw_input("Provide age"))
key = names_dict.keys()[names_dict.values().index(search_age)]
【讨论】:
你没有在下一行使用定义的search_age
var...也许你应该用search_age
替换value
?
我得到这个错误:'dict_values'对象没有属性'index'
@Blue_Elephant 你能提供代码 sn-p 你有错误和 python 版本(type(dict_values)
的打印也会有用)?
将names_dict.values().index(search_age)
更改为list(names_dict.values()).index(search_age)
解决了@Blue_Elephant 提出的问题。【参考方案12】:
我们可以通过以下方式获得dict
的Key
:
def getKey(dct,value):
return [key for key in dct if (dct[key] == value)]
【讨论】:
简单易懂,适用于独特的价值。【参考方案13】:这是我对这个问题的看法。 :) 我刚开始学习Python,所以我称之为:
“初学者可以理解”的解决方案。
#Code without comments.
list1 = 'george':16,'amber':19, 'Garry':19
search_age = raw_input("Provide age: ")
print
search_age = int(search_age)
listByAge =
for name, age in list1.items():
if age == search_age:
age = str(age)
results = name + " " +age
print results
age2 = int(age)
listByAge[name] = listByAge.get(name,0)+age2
print
print listByAge
.
#Code with comments.
#I've added another name with the same age to the list.
list1 = 'george':16,'amber':19, 'Garry':19
#Original code.
search_age = raw_input("Provide age: ")
print
#Because raw_input gives a string, we need to convert it to int,
#so we can search the dictionary list with it.
search_age = int(search_age)
#Here we define another empty dictionary, to store the results in a more
#permanent way.
listByAge =
#We use double variable iteration, so we get both the name and age
#on each run of the loop.
for name, age in list1.items():
#Here we check if the User Defined age = the age parameter
#for this run of the loop.
if age == search_age:
#Here we convert Age back to string, because we will concatenate it
#with the person's name.
age = str(age)
#Here we concatenate.
results = name + " " +age
#If you want just the names and ages displayed you can delete
#the code after "print results". If you want them stored, don't...
print results
#Here we create a second variable that uses the value of
#the age for the current person in the list.
#For example if "Anna" is "10", age2 = 10,
#integer value which we can use in addition.
age2 = int(age)
#Here we use the method that checks or creates values in dictionaries.
#We create a new entry for each name that matches the User Defined Age
#with default value of 0, and then we add the value from age2.
listByAge[name] = listByAge.get(name,0)+age2
#Here we print the new dictionary with the users with User Defined Age.
print
print listByAge
.
#Results
Running: *\test.py (Thu Jun 06 05:10:02 2013)
Provide age: 19
amber 19
Garry 19
'amber': 19, 'Garry': 19
Execution Successful!
【讨论】:
【参考方案14】:get_key = lambda v, d: next(k for k in d if d[k] is v)
【讨论】:
不错的单线。但是,is
应该仅用于单例的相等性测试(None
、True
、False
等)。 CPython 重用字符串文字(因此 a = 'foobar'; a is 'foobar'
是 True
)这一事实是一个实现细节,不应依赖。
还有一条评论:如果字典中不存在该值,get_key
将抛出 StopIteration
- 最好使用 next(..., None)
,如果该值返回 None
没有找到。
如果字典不包含单个元素而是集合,则稍作修改将起作用:get_first_key = lambda v, d: next((k for k in d if (v in d[k] is not None)), None)
【参考方案15】:
考虑使用 Pandas。正如 William McKinney 的“用于数据分析的 Python”中所述
另一种考虑系列的方式是定长、有序 dict,因为它是索引值到数据值的映射。有可能 在您可能使用字典的许多情况下使用。
import pandas as pd
list = 'george':16,'amber':19
lookup_list = pd.Series(list)
要查询您的系列,请执行以下操作:
lookup_list[lookup_list.values == 19]
产量:
Out[1]:
amber 19
dtype: int64
如果您需要对输出转换 回答到列表中可能会有用:
answer = lookup_list[lookup_list.values == 19].index
answer = pd.Index.tolist(answer)
【讨论】:
他是熊猫的创造者。不过,他通常被称为 Wes。【参考方案16】:d= 'george':16,'amber':19
dict((v,k) for k,v in d.items()).get(16)
输出如下:
-> prints george
【讨论】:
[k for k, v in d.items() if v==16]【参考方案17】:这里,recover_key 使用字典和值在字典中查找。然后我们循环遍历字典中的键,并与值的比较并返回该特定键。
def recover_key(dicty,value):
for a_key in dicty.keys():
if (dicty[a_key] == value):
return a_key
【讨论】:
【参考方案18】:for name in mydict:
if mydict[name] == search_age:
print(name)
#or do something else with it.
#if in a function append to a temporary list,
#then after the loop return the list
【讨论】:
使用 for 循环和追加比列表理解要慢得多,而且也更长。【参考方案19】:我只使用列表理解浏览了所有答案,但没有提及?
这个 Pythonic 单行解决方案可以返回任意数量给定值的所有键(在 Python 3.9.1 中测试):
>>> dictionary = 'george' : 16, 'amber' : 19, 'frank': 19
>>>
>>> age = 19
>>> name = [k for k in dictionary.keys() if dictionary[k] == age]; name
['george', 'frank']
>>>
>>> age = (16, 19)
>>> name = [k for k in dictionary.keys() if dictionary[k] in age]; name
['george', 'amber', 'frank']
>>>
>>> age = (22, 25)
>>> name = [k for k in dictionary.keys() if dictionary[k] in age]; name
[]
【讨论】:
【参考方案20】:my_dict = 'A': 19, 'B': 28, 'carson': 28
search_age = 28
只拿一个
name = next((name for name, age in my_dict.items() if age == search_age), None)
print(name) # 'B'
获取多个数据
name_list = [name for name, age in filter(lambda item: item[1] == search_age, my_dict.items())]
print(name_list) # ['B', 'carson']
【讨论】:
【参考方案21】:已回答,但可以通过花哨的“map/reduce”使用来完成,例如:
def find_key(value, dictionary):
return reduce(lambda x, y: x if x is not None else y,
map(lambda x: x[0] if x[1] == value else None,
dictionary.iteritems()))
【讨论】:
【参考方案22】:Cat Plus Plus 提到这不是字典的用途。原因如下:
字典的定义类似于数学中的映射。在这种情况下,字典是 K(键集)到 V(值)的映射,反之则不然。如果你取消引用一个字典,你期望得到一个返回的值。但是,不同的键映射到相同的值是完全合法的,例如:
d = k1 : v1, k2 : v2, k3 : v1
当您通过键的对应值查找键时,您实际上是在反转字典。但是映射不一定是可逆的!在这个例子中,请求对应于 v1 的键可以产生 k1 或 k3。你应该两个都退货吗?只找到第一个?这就是字典未定义 indexof() 的原因。
如果您知道自己的数据,则可以这样做。但是 API 不能假设任意字典是可逆的,因此缺少这样的操作。
【讨论】:
【参考方案23】:这是我的看法。这对于显示多个结果很有用,以防万一您需要一个。所以我也添加了列表
myList = 'george':16,'amber':19, 'rachel':19,
'david':15 #Setting the dictionary
result=[] #Making ready of the result list
search_age = int(input('Enter age '))
for keywords in myList.keys():
if myList[keywords] ==search_age:
result.append(keywords) #This part, we are making list of results
for res in result: #We are now printing the results
print(res)
就是这样……
【讨论】:
【参考方案24】:没有简单的方法可以通过“查找”值来找到列表中的键。但是,如果您知道值,遍历键,您可以按元素在字典中查找值。如果 D[element] 其中 D 是一个字典对象,等于您要查找的键,则可以执行一些代码。
D = 'Ali': 20, 'Marina': 12, 'George':16
age = int(input('enter age:\t'))
for element in D.keys():
if D[element] == age:
print(element)
【讨论】:
【参考方案25】:您需要使用字典和该字典的反向。这意味着您需要另一个数据结构。如果您使用的是 python 3,请使用 enum
模块,但如果您使用的是 python 2.7,请使用 enum34
,它是为 python 2 反向移植的。
例子:
from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<color.red: 1="">
>>> type(Color.red)
<enum 'color'="">
>>> isinstance(Color.green, Color)
True
>>> member = Color.red
>>> member.name
'red'
>>> member.value
1
【讨论】:
【参考方案26】:我尝试阅读尽可能多的解决方案,以防止给出重复的答案。但是,如果您正在处理列表中包含值的字典,并且想要获取具有特定元素的键,则可以这样做:
d = 'Adams': [18, 29, 30],
'Allen': [9, 27],
'Anderson': [24, 26],
'Bailey': [7, 30],
'Baker': [31, 7, 10, 19],
'Barnes': [22, 31, 10, 21],
'Bell': [2, 24, 17, 26]
现在让我们查找值中包含 24 的名称。
for key in d.keys():
if 24 in d[key]:
print(key)
这也适用于多个值。
【讨论】:
【参考方案27】:只是我在lambda
和filter
中的回答。
filter( lambda x, dictionary=dictionary, search_age=int(search_age): dictionary[x] == search_age , dictionary )
【讨论】:
【参考方案28】:已经回答了,但是由于有几个人提到了反转字典,下面是你如何在一行中做到这一点(假设 1:1 映射)和一些不同的性能数据:
python 2.6:
reversedict = dict([(value, key) for key, value in mydict.iteritems()])
2.7+:
reversedict = value:key for key, value in mydict.iteritems()
如果你认为不是 1:1,你仍然可以用几行创建一个合理的反向映射:
reversedict = defaultdict(list)
[reversedict[value].append(key) for key, value in mydict.iteritems()]
这有多慢:比简单的搜索要慢,但并不像您想象的那么慢 - 在“直接”100000 条目字典上,“快速”搜索(即寻找应该在早期的值键)比反转整个字典快大约 10 倍,“慢”搜索(接近结尾)大约快 4-5 倍。因此,在最多大约 10 次查找之后,它就收回了成本。
第二个版本(每个项目都有列表)大约是简单版本的 2.5 倍。
largedict = dict((x,x) for x in range(100000))
# Should be slow, has to search 90000 entries before it finds it
In [26]: %timeit largedict.keys()[largedict.values().index(90000)]
100 loops, best of 3: 4.81 ms per loop
# Should be fast, has to only search 9 entries to find it.
In [27]: %timeit largedict.keys()[largedict.values().index(9)]
100 loops, best of 3: 2.94 ms per loop
# How about using iterkeys() instead of keys()?
# These are faster, because you don't have to create the entire keys array.
# You DO have to create the entire values array - more on that later.
In [31]: %timeit islice(largedict.iterkeys(), largedict.values().index(90000))
100 loops, best of 3: 3.38 ms per loop
In [32]: %timeit islice(largedict.iterkeys(), largedict.values().index(9))
1000 loops, best of 3: 1.48 ms per loop
In [24]: %timeit reversedict = dict([(value, key) for key, value in largedict.iteritems()])
10 loops, best of 3: 22.9 ms per loop
In [23]: %%timeit
....: reversedict = defaultdict(list)
....: [reversedict[value].append(key) for key, value in largedict.iteritems()]
....:
10 loops, best of 3: 53.6 ms per loop
使用 ifilter 也有一些有趣的结果。从理论上讲,ifilter 应该更快,因为我们可以使用 itervalues() 并且可能不必创建/遍历整个值列表。在实践中,结果……很奇怪……
In [72]: %%timeit
....: myf = ifilter(lambda x: x[1] == 90000, largedict.iteritems())
....: myf.next()[0]
....:
100 loops, best of 3: 15.1 ms per loop
In [73]: %%timeit
....: myf = ifilter(lambda x: x[1] == 9, largedict.iteritems())
....: myf.next()[0]
....:
100000 loops, best of 3: 2.36 us per loop
因此,对于小偏移量,它比任何以前的版本都快得多(2.36 *u*S 与以前的情况下至少 1.48 *m*S)。但是,对于列表末尾附近的大偏移量,它的速度要慢得多(15.1ms 与相同的 1.48mS)。低端的小额节省不值得高端的成本,恕我直言。
【讨论】:
我非常希望这个 (reversedict = defaultdict(list) reversedict[value].append(key) for key, value in largedict.iteritems()] ) 工作,但使用 Python 2.7.3 ,我在单词“for”上出现语法错误 这是您实际输入的内容吗?如果是,您在其中缺少[
。否则,请确保它在两行上,如果不是,则在它们之间放置一个;
。【参考方案29】:
这是您访问字典以执行您想要的操作的方式:
list = 'george': 16, 'amber': 19
search_age = raw_input("Provide age")
for age in list:
if list[age] == search_age:
print age
当然,你的名字太离谱了,它看起来像是在打印一个年龄,但它确实打印了这个名字。由于您是按名称访问的,因此如果您这样写会更容易理解:
list = 'george': 16, 'amber': 19
search_age = raw_input("Provide age")
for name in list:
if list[name] == search_age:
print name
更好:
people = 'george': 'age': 16, 'amber': 'age': 19
search_age = raw_input("Provide age")
for name in people:
if people[name]['age'] == search_age:
print name
【讨论】:
【参考方案30】:def get_Value(dic,value):
for name in dic:
if dic[name] == value:
del dic[name]
return name
【讨论】:
为什么要从字典中删除键?没有回答问题以上是关于在字典中按值获取键的主要内容,如果未能解决你的问题,请参考以下文章