Подтвердить что ты не робот

Поиск ключа из значения в словаре Python:

Довольно новый для Python, все еще борющийся с таким количеством информации.

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

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

4b9b3361

Ответ 1

Прямого маршрута нет. Это довольно легко с учетом списка, однако;

[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, кроме наоборот.

Вы также можете создать класс, который автоматически индексировал его оба раза. Тогда ключ и значение должны были быть хешируемыми. Вот три способа его реализации:

  • В двух отдельных dicts с разоблачением некоторых диктоподобных методов; вы могли бы сделать 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)
    

(Заметно отсутствует в этих реализациях a bidict метод update, который будет немного более сложным (но help(dict.update) укажет, что вам нужно будет покрыть). Без update, bidict({1:2}) не будет делать то, на что он предназначен, и не будет d.update({1:2}).)

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

Ответ 2

Так как ваш словарь может содержать повторяющиеся значения (т.е. {'a': 'A', 'b': 'A'}), единственный способ найти ключ от значения - перебирать словарь по описанию.

Или... создайте противоположный словарь. вы должны воссоздать его после каждой модификации исходного словаря.

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

Ответ 3

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

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

Ответ 4

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