在Python字典中从值查找键:

17 投票
4 回答
46198 浏览
提问于 2025-04-17 03:42

我刚接触Python,感觉信息量太大,有点吃力。

我看到的所有关于字典的文档都在讲怎么通过键来获取值,但我想找一种更“Python风格”的方法,反过来通过值来获取键。

我知道可以通过循环遍历所有的键,检查它们的值,直到找到我想要的值,然后再拿到对应的键,但我想要一种更直接的方法。

4 个回答

1

第一个用列表推导式的解决方案很好。不过对于Python 3.x,有个小修正,应该用.items(),而不是.iteritems()

[k for k, v in d.items() if v == desired_value]
6

因为你的字典可以包含重复的值(比如 {'a': 'A', 'b': 'A'}),所以要从值找到对应的键,唯一的方法就是像你说的那样一个一个遍历字典。

或者……你可以建立一个反向字典。每次修改原始字典后,你都得重新创建这个反向字典。

或者……你可以写一个类,来同时维护一个双向字典。这样的话,你需要处理出现重复值的情况。

31

没有直接的解决办法。不过,用列表推导式来做这件事其实挺简单的。

[k for k, v in d.iteritems() if v == desired_value]

如果你只是偶尔需要这样做,并且觉得不值得反向索引的话,你可以试试下面的方法:

class bidict(dict):
    def key_with_value(self, value, default=None):
        for k, v in self.iteritems():
            if v == value:
                return v
        return default

    def keys_with_value(self, value, default=None):
        return [v for k, v in self.iteritems() if v == value]

这样的话,d.key_with_value 的表现就像 d.get,不过是反过来的。

你也可以创建一个类,让它自动支持双向索引。这样,键和值都需要是可哈希的。下面是三种可以实现的方法:

  • 用两个独立的字典,并提供一些类似字典的方法;你可以用 foo.by_key[key]foo.by_value[value] 来访问。(这里没有给出代码,因为这比较复杂,我有点懒,而且我觉得这样实现并不是最优的。)

  • 用另一种结构,这样你可以用 d[key]d.inverse[value] 来访问:

    class bidict(dict):
        def __init__(self, *args, **kwargs):
            self.inverse = {}
            super(bidict, self).__init__(key, value)
    
        def __setitem__(self, key, value):
            super(bidict, self).__setitem__(key, value)
            self.inverse[value] = key
    
        def __delitem__(self, key):
            del self.inverse[self[key]]
            super(bidict, self).__delitem__(key)
    
  • 用同一种结构,这样你可以用 d[key]d[value] 来访问:

    class bidict(dict):
        def __setitem__(self, key, value):
            super(bidict, self).__setitem__(key, value)
            super(bidict, self).__setitem__(value, key)
    
        def __delitem__(self, key):
            super(bidict, self).__delitem__(self[key])
            super(bidict, self).__delitem__(key)
    

值得注意的是,这些 bidict 的实现中缺少了 update 方法,这个方法会稍微复杂一些(不过 help(dict.update) 会告诉你需要覆盖哪些内容)。如果没有 update,那么 bidict({1:2}) 就无法按预期工作,d.update({1:2}) 也是如此。

另外,考虑一下是否有其他数据结构更合适。

撰写回答