I have two lists:
list1 = [ {'sth': 13, 'important_key1': 'AA', 'important_key2': '3'}, {'oh!': 14, 'important_key1': 'FF', 'important_key2': '4'}, {'sth_else': 'abc', 'important_key1': 'ZZ', 'important_key2': '5'}]
list2 = [ {'why-not': 'tAk', 'important_key1': 'GG', 'important_key2': '4'}, {'hmmm': 'no', 'important_key1': 'AA', 'important_key2': '3'}]
I want to return a list with objects only from list1 but if the same important_key1
and important_key2
is in any element in list2 I want this element from list2.
So the output should be:
[ {'hmmm': 'no', 'important_key1': 'AA', 'important_key2': '3'}, {'oh!': 14, 'important_key1': 'FF', 'important_key2': '4'}, {'sth_else': 'abc', 'important_key1': 'ZZ', 'important_key2': '5'}]
It is not complicated to do it by two or three loops but I wonder whether there is a simple way by using list comprehensions or something like that.
This is the "normal" way:
list1 = [ {'sth': 13, 'important_key1': 'AA', 'important_key2': '3'}, {'oh!': 14, 'important_key1': 'FF', 'important_key2': '4'}]
list2 = [ {'hmmm': 'no', 'important_key1': 'AA', 'important_key2': '3'}, {'why-not': 'tAk', 'important_key1': 'GG', 'important_key2': '4'}]
final_list = []
for element in list1:
there_was_in_list2 = False
for another_element in list2:
if element['important_key1'] == another_element['important_key1'] and element['important_key2'] == another_element['important_key2']:
final_list.append(another_element)
there_was_in_list2 = True
break
if not there_was_in_list2:
final_list.append(element)
print(final_list)
is there any Pythonic way to do that?
To merge a list of dicts into a single dict with Python, we can use reduce function from the functools module. We call reduce with a function that merges dictionary a with the entries in b and return it. a and b are both entries in list_of_dicts .
In python, we can use the + operator to merge the contents of two lists into a new list. For example, We can use + operator to merge two lists i.e. It returned a new concatenated lists, which contains the contents of both list_1 and list_2.
You can use a list comprehension:
list1 = [{'sth': 13, 'important_key1': 'AA', 'important_key2': '3'}, {'oh!': 14, 'important_key1': 'FF', 'important_key2': '4'}]
list2 = [{'hmmm': 'no', 'important_key1': 'AA', 'important_key2': '3'}, {'why-not': 'tAk', 'important_key1': 'GG', 'important_key2': '4'}]
vals = ['important_key1', 'important_key2']
new_list = [[c if any(c[a] == i[a] for a in vals) else i for c in list2] for i in list1]
final_result = [i[0] for i in new_list if i]
Output:
[{'hmmm': 'no', 'important_key1': 'AA', 'important_key2': '3'}, {'oh!': 14, 'important_key1': 'FF', 'important_key2': '4'}]
You can convert list2
to a dict indexed by a tuple of the values the important keys in list2
, and then use it to determine if the same keys in list1
have the same values as you iterate through list1
in a list comprehension, so that the time complexity gets reduced to O(n) from your O(n*m):
keys = ['important_key1', 'important_key2']
d2 = {tuple(d[k] for k in keys): d for d in list2[::-1]}
print([d2.get(tuple(d[k] for k in keys), d) for d in list1])
This outputs (with your sample input):
[{'hmmm': 'no', 'important_key1': 'AA', 'important_key2': '3'}, {'oh!': 14, 'important_key1': 'FF', 'important_key2': '4'}, {'sth_else': 'abc', 'important_key1': 'ZZ', 'important_key2': '5'}]
As you described in your question, only {'sth': 13, 'important_key1': 'AA', 'important_key2': '3'}
in list1
would get replaced by {'hmmm': 'no', 'important_key1': 'AA', 'important_key2': '3'}
because only this dict has both important_key1
and important_key2
matching those of a dict in list2
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With