Проверьте, содержится ли данный ключ в любом из нескольких словарей - PullRequest
5 голосов
/ 02 апреля 2020

У меня есть несколько словарей, которые содержат данные в зависимости от их коммерческой ценности, например:

companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}
...

Мне нужно проверить, содержится ли переменная x в каком-либо из этих словарей, и определить, в каких из этих словарей он содержится. Количество таких словарей может быть огромным, поэтому проверка их вручную не очень эффективна. Есть ли что-то более питонское c, чем

if x in companies:
    pass    # do something
elif x in names:
    pass    # do something
...

Ответы [ 7 ]

4 голосов
/ 02 апреля 2020

Простой / быстрый код: l oop в списке словарей, остановитесь, когда найдете его.

Но сложность не хороша, если вы выполните несколько поисков. Вместо этого создайте словарь из своих словарей.

  • Ключи представляют собой объединение ключей
  • Значения представляют собой списки пар (значение, происхождение dict)

вот так:

companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}

import collections

c = collections.defaultdict(list)

for d in [companies,names]:
    for k,v in d.items():
        c[k].append((v,d))

сейчас:

print(c.get('google'))

печатает:

[('value_1', {'google': 'value_1', 'facebook': 'value_2'})

Теперь, если я добавлю общий ключ в оба слова:

names = {'alex': 'value_3', 'john': 'value_4', 'facebook':'value_5'}
print(c.get('facebook'))

мы получаем список всех значений и исходных словарей:

[('value_2', {'google': 'value_1', 'facebook': 'value_2'}),
 ('value_5', {'alex': 'value_3', 'john': 'value_4', 'facebook': 'value_5'})]

С этим решением, даже если у вас много словарей, поиск всегда будет O(1) когда новый большой словарь построен . Сборка амортизируется после 2 или 3 поисков.

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

3 голосов
/ 02 апреля 2020

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

In таким образом, вы будете oop обходить все словари, чтобы построить свою 'справочную таблицу', и тогда каждый доступ к 'x' больше не будет нуждаться в зацикливании.

Например:

my_dicts = {'companies': {'google': 'value_1', 'facebook': 'value_2', 'alex': 'yo'},
            'names': {'alex': 'value_3', 'john': 'value_4'}}

# build the lookup dict
lookup = {}
for dk, dv in my_dicts.items():
    for k in dv.keys():
        dl = lookup.get(k, [])
        lookup[k] = dl + [dk]

Теперь вы можете напрямую получить доступ к словарям, которые имеют ваш ключ x:

x = 'alex'
dict_names = lookup[x]

for dn in dict_names:
    # do something on my_dict[dn]
    print(dn)

названия компаний

3 голосов
/ 02 апреля 2020

Я бы использовал list для хранения всех словарей, а затем просто отфильтровал те, которые не содержат ваш ключ, используя понимание списка:

companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}

x = 'john'

dicts = [companies, names]

contains_key = [d for d in dicts if x in d]

Для большого числа словари, скажем тысячи, это не масштабируется так же хорошо, как ответ @ Jean-François Fabre, но это простой подход

3 голосов
/ 02 апреля 2020

Вы можете составить список с этими словарями:

dictionaries = [companies, names]

for dictionary in dictionaries:
        if keyword in dictionary:
2 голосов
/ 02 апреля 2020

Простым способом было бы поместить словари в список, выполнить итерацию каждого словаря и проверить, существует ли x в каждом словаре:

from json import dumps

companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}

lst = [companies, names]

x = 'google'

for dic in lst:
    if x in dic:
        print('%s exists in dict %s' %(key, dumps(dic)))

# google exists in dict {"google": "value_1", "facebook": "value_2"}

Но это медленно, потому что вам нужно повторять каждый словарь в списке для поиска. Это будет O(D) для каждого поиска, где D - количество словарей в списке.

Более быстрый способ - использовать defaultdict(list) для сбора словарей для каждого ключа, тогда последующие поиски будут O(1). Однако создание этого словаря будет операцией O(D * K) (D = количество словарей, K = количество ключей в словаре), потому что нам нужно повторять каждый dict и его ключи. Если вы делаете много поисков, то это преобразование будет иметь смысл в долгосрочной перспективе.

from collections import defaultdict
from json import dumps

companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}

lst = [companies, names]

x = 'google'

all_dicts = defaultdict(list)
for dic in lst:
    for key in dic:
        all_dicts[key].append(dic)

print("%s exists in these dictionaries : %s" % (x, dumps(all_dicts[x])))
# google exists in these dictionaries : [{"google": "value_1", "facebook": "value_2"}]
2 голосов
/ 02 апреля 2020

Способ:

  • Используйте filter, чтобы найти дикты, где находится ключ search_key
  • Используйте next(), чтобы выполнить итерацию один раз, чтобы получить первый (получить любой на самом деле)
  • используйте параметр default, чтобы избежать StopIteration (вы также можете вернуть dict next(..., {})
def find_dict(x, *dicts):
    return next(filter(lambda d: x in d, dicts), None)

Использование:

if __name__ == '__main__':
    companies = {'google': 'value_1', 'facebook': 'value_2'}
    names = {'alex': 'value_3', 'john': 'value_4'}
    x = 'alex'

    print(find_dict(x, companies, names)) # {'alex': 'value_3', 'john': 'value_4'}
    print(find_dict('foo', companies, names)) # None
1 голос
/ 02 апреля 2020

Python объекты ключевых слов словаря на самом деле похожи на наборы. Вы можете легко сделать из них набор:

>>> a = {'a':1, 'b':2}
>>> b = {'a':2, 'c':3}
>>> a.keys() | b.keys()
{'a', 'b', 'c'}

Теперь все, что вам нужно сделать, это проверить членство в наборе

>>> if x in that_set: ...

Если у вас большое количество словарей, вы можете посмотреть на этот ответ , чтобы узнать, как объединить множество множеств, но имейте в виду, что set.union(dict.keys()) недопустимо ...

>>> set.union(a.keys())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor 'union' for 'set' objects doesn't apply to a 'dict_keys' object

, поэтому вам нужно сделать что-то вроде

>>> all_keys = set.union(*(set(d) for d in all_dicts))

явное приведение каждого словаря к набору в понимании.

Конечно, вы также можете объединить все словари , чтобы получить аналогичный эффект :

>>> all_dicts = {**dict1, **dict2, **dict3}
>>> "key" in all_dicts

Это все еще очень эффективный способ найти хотя бы одно значение во всех словарях для данного ключа, даже если он все еще не сообщает вам, в каком из словарей был ключ. Для этого, боюсь, вы должны повторить. Прекрасный ответ Азро говорит вам, как это сделать.

...