У меня есть два списка словарей:
dict_list1 = [{'k1':1, 'k2':2}, {'k1':3, 'k2':4}]
dict_list2 = [{'k1':1, 'k2':2, 'k3':10}, {'k1':3, 'k2':4, 'k3':10}]
И теперь для каждого dict_x в dict_list1 я хочу знать, есть ли dict_y в dict_list2, который содержит каждый ключ, значение из dict_x.
Я не могу придумать другого способа сделать это, кроме этого:
for dict_x in dict_list1:
for dict_y in dict_list2:
count = len(dict_x)
for key, val in dict_x.items():
if key in dict_y and dict_y[key] == val:
count -= 1
if count == 0:
print('YAY')
break
Вы можете использовать any
и all
:
dict_list1 = [{'k1':1, 'k2':2}, {'k1':3, 'k2':4}]
dict_list2 = [{'k1':1, 'k2':2, 'k3':10}, {'k1':3, 'k2':4, 'k3':10}]
v = [any(all(c in i and i[c] == k for c, k in b.items()) for i in dict_list2)\
for b in dict_list1]
Выход:
[True, True]
Кроме того, разве у него нет нескольких петель, просто вставленных в однострочник?
Да, я полагаю, есть еще 3 форса, но в одной строке
Попробуйте dict_list1 = [{'k1':1, 'k2': None}]
и dict_list2 = [{'k1':1}]
.
Ниже я использую тот факт, что Представление dict.items
реализует операции set
для проверки каждого d1.items()
, существует ли d2.items()
, так что d1.items()
является подмножеством d2.items()
.
[any(d1.items() <= d2.items() for d2 in dict_list2) for d1 in dict_list1]
Моя текущая версия возвращает список длиной dict_list1
, представляющий, является ли какой-либо элемент dict_list2
суперсредством словаря по этому индексу в dict_list1
.
Представления dict
могут выполнять быстрое тестирование "подмножества" с помощью операторов неравенства. Так:
if dict_x.items() <= dict_y.items(): # Use .viewitems() instead of .items() on Python 2.7
вернет истину только в том случае, если каждая пара ключ / значение в dict_x
также присутствует в dict_y
.
Это ничего не изменит с точки зрения производительности big-O, но сделает код несколько чище:
for dict_x in dict_list1:
for dict_y in dict_list2:
if dict_x.items() <= dict_y.items():
print('YAY')
break
Обратите внимание, что создание представлений стоит что-то (это просто фиксированная стоимость, не зависящая от размера dict
), поэтому, если производительность имеет значение, возможно, стоит кэшировать представления; для dict_list1
это бесплатно:
for dict_x in dict_list1:
dict_x_view = dict_x.items()
for dict_y in dict_list2:
if dict_x_view <= dict_y.items():
print('YAY')
break
но для кеширования обоих потребуются некоторые активные преобразования:
# Convert all of dict_list2 to views up front; costs a little if
# not all views end up being tested (we always break before finishing)
# but usually saves some work at the cost of a tiny amount of memory
dict_list2_views = [x.items() for x in dict_list2]
for dict_x in dict_list1:
dict_x_view = dict_x.items()
for dict_y_view in dict_list2_views:
if dict_x_view <= dict_y_view:
print('YAY')
break
Вы также можете свернуть цикл с помощью any
(что устраняет необходимость в break
из-за короткого замыкания any
), поэтому первая (простейшая) проверка может выглядеть так:
for dict_x in dict_list1:
if any(dict_x.items() <= dict_y.items() for dict_y in dict_list2):
print('YAY')
В дальнейшем это можно было бы свести к единому списку, который приводит к различным совпадениям, но в этот момент код будет довольно тесным / уродливым:
for _ in (dict_x in dict_list1 if any(dict_x.items() <= dict_y.items() for dict_y in dict_list2)):
print('YAY')
хотя, не зная, что бы вы на самом деле сделали (а не просто печатать YAY
), это становится немного бессмысленным.
Принятие ответа @ShadowRanger, потому что он более полный.
Это проверяет только ключи, но не значения.