通过字典中的值获取键


632

我制作了一个函数,该函数将查询年龄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

我知道如何比较和查找年龄,但我不知道如何显示此人的名字。另外,KeyError由于第5行,我得到了提示。我知道这是不正确的,但我不知道如何使它向后搜索。



您会根据字典中的定义找到单词吗?不。
Jossie Calderon

Answers:


563

空无一人。 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)

137
Python 3.x list.items()而不是list.iteritems()应该使用
Yuriy Petrovskiy

63
我不同意...以下agf的答案更具建设性。完美合理的用例不是“意外”的(列表理解仍然适合这种用例)。A dict可以在不同时间代表多个事物;键和值当然具有明确的含义,但是dict具有给定值的项目”是一个完全合理的要求。建议使用成对的列表将放弃上下文,即一个项目是另一个项目的“ 定义 ”,例如在参数列表中……
Louis Maddox

1
我不同意这个答案。正如斯特尼奥·埃尔森(StênioElson)的回答所显示的那样,这是一种可能性的事实,并不意味着它并不打算被如此使用。完全没有帮助。
Tropicalrambler

您会根据词典的定义在词典中找到一个单词吗?不。@Tropicalrambler
Jossie Calderon

尽管您认为单词词典的标准用法是使用单词=键和定义=值来搜索单词的定义,但是当今的编程语言使您能够在必要时按值搜索。如果您正在使用key:value对对象(将其称为字典,元组,任何语言的任何名称)。在python中,事实是您仍然可以在结构的值中建立索引以找出相应的键。
热带

599
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()如何从dict中获取值列表?.values()


23
看起来不错,但是可以一直使用吗?我的意思是,list.keys()list.values()功能产生相同的顺序?
iskorum 2013年

17
是的,我们保证它们是一致的。另外,只要不修改字典,就可以保证顺序不会在迭代中改变。
Veedrac

9
这看起来是一个很好的解决方案,但是索引只赋予了一个正确的值,因此,如果您拥有多个相等的值,那么它应该返回多个键对吗?
詹姆斯·萨帕姆

12
@ArtOfWarfare docs.python.org/3/library/stdtypes.html#dict-views,“如果迭代了键,值和项视图,而没有对字典进行任何中间修改,则项的顺序将直接对应。”
Veedrac

5
@sinekonata:它仍然在引擎盖下执行昂贵的循环;循环只是隐藏在index方法内部。
user2357112支持Monica 2016年

252

如果你想同时姓名年龄,你应该用.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在其答案中所做的操作,因为它不需要复制列表。


9
正确,但是如果您要进行线性搜索,则最好将其替换dict为成对列表。
弗雷德·富

9
除非您的常规操作是按名称查找年龄,否则这dict是有道理的。
2011年

2
假设每个年龄段只有一个人似乎是奇怪的,另一方面,每个人只有一个年龄段是完全合乎逻辑的。
丹妮德

@Dannid是的,但是这个问题很容易泛化。例如,您可能有一个具有唯一键及其对应的唯一值的查找表。然后,您可以对称查找内容,value --> key或者key --> value
pfabri

67

我认为指出哪种方法最快,在哪种情况下会很有趣:

这是我运行的一些测试(在2012年的MacBook Pro上)

>>> def method1(list,search_age):
...     for name,age in list.iteritems():
...             if age == search_age:
...                     return name
... 
>>> def method2(list,search_age):
...     return [name for name,age in list.iteritems() if age == search_age]
... 
>>> def method3(list,search_age):
...     return list.keys()[list.values().index(search_age)]

profile.run()每种方法的结果100000次:

方法1:

>>> profile.run("for i in range(0,100000): method1(list,16)")
     200004 function calls in 1.173 seconds

方法2:

>>> profile.run("for i in range(0,100000): method2(list,16)")
     200004 function calls in 1.222 seconds

方法3:

>>> profile.run("for i in range(0,100000): method3(list,16)")
     400004 function calls in 2.125 seconds

因此,这表明对于小的字典而言,方法1最快。这很可能是因为它返回第一个匹配项,而不是像方法2那样的所有匹配项(请参见下面的注释)。


有趣的是,对我拥有2700个条目的字典执行相同的测试,我得到的结果却截然不同(这次运行10000次):

方法1:

>>> profile.run("for i in range(0,10000): method1(UIC_CRS,'7088380')")
     20004 function calls in 2.928 seconds

方法2:

>>> profile.run("for i in range(0,10000): method2(UIC_CRS,'7088380')")
     20004 function calls in 3.872 seconds

方法3:

>>> profile.run("for i in range(0,10000): method3(UIC_CRS,'7088380')")
     40004 function calls in 1.176 seconds

所以在这里,方法3是快。只是显示您的字典大小会影响您选择的方法。

注意:方法2返回所有名称的列表,而方法1和3仅返回第一个匹配项。我没有考虑内存使用情况。我不确定方法3是否创建2个额外的列表(keys()和values())并将其存储在内存中。


6
只是更新:似乎dict.values()和dict.keys()都返回引用原始dict中对象的列表,因此方法3也是使用最少内存的方法(它仅创建两个精简列表对象其中包装了命令的内容,而其他命令则创建了迭代器项
Patrick

我只是想自己对它进行基准测试,向下滚动,就可以找到它了。谢谢!正如您已经指出的,从技术上讲,方法2与1和3并不完全相同,因为它返回所有匹配项。很高兴看到例如return next([..])的结果。
BluBb_mADe15年

另一个需要注意的重要事项是Python版本。我知道某些版本比其他版本具有更有效的方法实现。
ArtOfWarfare 2015年

@Patrick:所有方法都使用对值和键的直接引用,任何方法都没有内存优势。除了在Python 3 .keys()和` .values()返回字典视图,这是重量轻的。
马丁·彼得斯

53

一线版本:(i是旧字典,p是反向字典)

说明:i.keys()i.values()返回两个分别具有字典键和值的列表。zip函数具有将列表捆绑在一起以生成字典的能力。

p = dict(zip(i.values(),i.keys()))

警告:仅当值是可哈希值且唯一时,此选项才起作用。



17
...并且没有重复值。
2014年

3
美丽。上面的注释当然只有在没有重复值的情况下才起作用,但是,以该线程开头的问题使我们假设我们具有一对一的功能,因此鉴于此假设,这是最优雅的到目前为止的反应。
约翰·斯特朗

1
扩展可散列值:如果您的值是列表/集合,则将它们转换为元组才能正常工作(它们仍然需要唯一)。
muon

28
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}

5
如果还有另一个键具有相同的a值,该怎么办?可能是pythonic方式。但是不是一个好主意。
7H3 IN5ID3R

好点,我添加了适用于非唯一值的解决方案
Jelen

25
key = next((k for k in my_dict if my_dict[k] == val), None)

我在同一行中也可以有一个“ else”吗?对于我的值不在dict值中的情况
Srishti Gupta,

lKey = [k for k, v in lDictionary.iteritems() if v == lValue][0] or 'else-key'
faham


13

我找到了这个答案非常有效,但对我来说却不太容易理解。

为了更加清晰,您可以反转字典的键和值。这是使键的值和值的键,因为看到这里

mydict = {'george':16,'amber':19}
res = dict((v,k) for k,v in mydict.iteritems())
print(res[16]) # Prints george

要么

mydict = {'george':16,'amber':19}
dict((v,k) for k,v in mydict.iteritems())[16]

这与其他答案基本相同。



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)]

2
您不要search_age在下一行使用已定义的var ...也许您应该替换valuesearch_age
Andersson

2
我收到此错误:'dict_values'对象没有属性'
index'– Blue_Elephant

@Blue_Elephant能否提供您有错误和python版本的代码段(也可以打印出来type(dict_values))?
Andriy Ivaneyko '17

9

这是我对这个问题的看法。:)我刚刚开始学习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!

9
get_key = lambda v, d: next(k for k in d if d[k] is v)

很好的一线。然而,is应仅用于单身平等测试(使用NoneTrueFalse等等)。CPython重用字符串文字(因此a = 'foobar'; a is 'foobar'True)的事实是实现细节,因此不应依赖。
piit79 '19

1
还有一条评论:如果字典中不存在该值,get_key则会抛出StopIteration该错误-最好使用在找不到该值时next(..., None)会返回None的值。
piit79 '19

如果字典中不包含单个元素而是进行设置,则可以进行一些小的修改:get_first_key = lambda v, d: next((k for k in d if (v in d[k] is not None)), None)
超新星

7

考虑使用熊猫。正如William McKinney的“ Python for Data Analysis”中所述

考虑序列的另一种方法是定长排序的字典,因为它是索引值到数据值的映射。它可以在可能使用字典的许多情况下使用。

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)

他是熊猫的创造者。不过,他通常被称为韦斯。
Axel

6

在这里,recover_key将使用字典和要在字典中找到的值。然后,我们遍历字典中的键,并与value的键进行比较,然后返回该特定键。

def recover_key(dicty,value):
    for a_key in dicty.keys():
        if (dicty[a_key] == value):
            return a_key

4
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

1
使用for循环和追加操作比列表理解要慢得多,并且也更长。
alexpinho98


3

它得到了回答,但是可以通过使用“ 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()))

3

Cat Plus Plus提到,这不是打算使用字典的方式。原因如下:

字典的定义类似于数学中的映射。在这种情况下,字典是K(键集)到V(值)的映射-但反之亦然。如果取消引用dict,则期望返回的值恰好是一个。但是,将不同的键映射到相同的值是完全合法的,例如:

d = { k1 : v1, k2 : v2, k3 : v1}

当您通过键的对应值查找键时,实际上就是在反转字典。但是,映射不一定是可逆的!在此示例中,请求对应于v1的密钥可能会产生k1或k3。您应该同时退货吗?只是找到第一个?这就是为什么字典未定义indexof()的原因。

如果您知道自己的数据,则可以这样做。但是API不能假定任意字典都是可逆的,因此缺少这种操作。


3

这是我的看法。万一您需要一个结果,这对于显示多个结果很有用。所以我也添加了列表

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)

就是这样...


3
d= {'george':16,'amber':19}

dict((v,k) for k,v in d.items()).get(16)

输出如下:

-> prints george

[k代表k,k代表d.items()中的v,如果v == 16]
auro

3

没有一种简单的方法可以通过“查找”值在列表中找到键。但是,如果您知道该值(通过键进行迭代),则可以通过该元素在字典中查找值。如果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)

3

您需要使用字典,然后反向使用该字典。这意味着您需要另一个数据结构。如果您使用的是python 3,请使用enum模块,但如果使用的是python 2.7,请使用enum34python 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 


2

只是我的回答lambdafilter

filter( lambda x, dictionary=dictionary, search_age=int(search_age): dictionary[x] == search_age  , dictionary )

1

已经回答了,但是由于有几个人提到反转字典,因此这是您在一行中进行操作的方式(假设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),largedict.iteritems()]中的值)有效,但是使用Python 2.7.3时,该单词出现语法错误“为”
slashdottir 2014年

这是您实际键入的内容吗?如果是[,则缺少其中的一个。否则,请确保它在两行上,;如果不在两行之间,请在它们之间放一个。
Corley Brigman 2014年

1

有时可能需要int():

titleDic = {'Фильмы':1, 'Музыка':2}

def categoryTitleForNumber(self, num):
    search_title = ''
    for title, titleNum in self.titleDic.items():
        if int(titleNum) == int(num):
            search_title = title
    return search_title

1

这是一个在Python 2和Python 3中都可以使用的解决方案。

dict((v, k) for k, v in list.items())[search_age]

直到[search_age]构造反向字典为止(其中值是键,反之亦然)。您可以创建一个辅助方法,该方法将缓存此反向字典,如下所示:

def find_name(age, _rev_lookup=dict((v, k) for k, v in ages_by_name.items())):
    return _rev_lookup[age]

甚至更一般的工厂将为您的一个或多个列表创建按年龄查找名称的方法

def create_name_finder(ages_by_name):
    names_by_age = dict((v, k) for k, v in ages_by_name.items())
    def find_name(age):
      return names_by_age[age]

这样您就可以执行以下操作:

find_teen_by_age = create_name_finder({'george':16,'amber':19})
...
find_teen_by_age(search_age)

请注意,由于前者是预定义类型,因此我将其重命名listages_by_name


1

这是您访问字典以执行所需操作的方式:

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

1
dictionary = {'george' : 16, 'amber' : 19}
search_age = raw_input("Provide age")
key = [filter( lambda x: dictionary[x] == k  , dictionary ),[None]][0] 
# key = None from [None] which is a safeguard for not found.

对于多次出现,请使用:

keys = [filter( lambda x: dictionary[x] == k  , dictionary )]

*** NameError: global name 'dictionary' is not defined
比什瓦斯·米什拉

filter( lambda x, dictionary=dictionary, search_age=int(search_age): dictionary[x] == search_age , dictionary )
比什瓦斯·米什拉
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.