Поиск ключа по значению в словаре Python: - PullRequest
13 голосов
/ 05 октября 2011

Довольно плохо знаком с Python, все еще борясь с таким большим количеством информации.

Вся документация, которую я видел о словарях, объясняет различные способы получения значения через ключ - но я ищу питонский способ сделать обратное - получить ключ через значение.

Я знаю, что могу перебирать ключи и проверять их значения, пока не найду нужное значение, а затем схватить ключ, но я ищу прямой маршрут.

Ответы [ 4 ]

27 голосов
/ 05 октября 2011

Прямого маршрута нет.Однако это довольно просто для списочных представлений:

[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}).)

Также подумайте, будет ли более подходящей какая-либо другая структура данных.

6 голосов
/ 05 октября 2011

Поскольку ваш словарь может содержать повторяющиеся значения (т. Е. {'a': 'A', 'b': 'A'}), единственный способ найти ключ из значения - это перебирать словарь, как вы описываете.,Вы должны воссоздавать его после каждой модификации исходного словаря.

Или ... написать класс, который поддерживает двусторонний словарь.Вам придется управлять ситуациями, когда появляется повторяющееся значение.

1 голос
/ 05 декабря 2017

первое решение с пониманием списка хорошее.но небольшое исправление для python 3.x вместо .iteritems() должно быть просто .items():

[k for k, v in d.items() if v == desired_value]
0 голосов
/ 07 марта 2016

Создание противоположного словаря совсем не годится, так как один или несколько ключей имеют одинаковое значение, но если вы инвертируете его, вам нужно вставить структуру key: [value1, ...], которая приведет вас к другой проблеме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...