In python 3.5 or higher, you can merge dictionaries in a single statement.
So for python 3.5 or higher, a quick solution would be:
from itertools import zip_longest
l3 = [{**u, **v} for u, v in zip_longest[l1, l2, fillvalue={}]]
print[l3]
#[
# {'index': 1, 'b': 2, 'c': 4},
# {'index': 2, 'b': 3, 'c': 5},
# {'index': 3, 'green': 'eggs'}
#]
However if the two lists were the same size, you could simply use zip:
l3 = [{**u, **v} for u, v in zip[l1, l2]]
Note: This assumes that the lists are sorted the same way by index
, which is
stated by OP to not be the case in general.
In order to generalize for that case, one way is to create a custom zip-longest type function which yields values from the two lists only if they match on a key.
For instance:
def sortedZipLongest[l1, l2, key, fillvalue={}]:
l1 = iter[sorted[l1, key=lambda x: x[key]]]
l2 = iter[sorted[l2, key=lambda x: x[key]]]
u = next[l1, None]
v = next[l2, None]
while [u is not None] or [v is not None]:
if u is None:
yield fillvalue, v
v = next[l2, None]
elif v is None:
yield u, fillvalue
u = next[l1, None]
elif u.get[key] == v.get[key]:
yield u, v
u = next[l1, None]
v = next[l2, None]
elif u.get[key] < v.get[key]:
yield u, fillvalue
u = next[l1, None]
else:
yield fillvalue, v
v = next[l2, None]
Now if you had the following out of order lists:
l1 = [{"index":1, "b":2}, {"index":2, "b":3}, {"index":3, "green":"eggs"},
{"index":4, "b": 4}]
l2 = [{"index":1, "c":4}, {"index":2, "c":5}, {"index":0, "green": "ham"},
{"index":4, "green": "ham"}]
Using the sortedZipLongest
function instead of
itertools.zip_longest
:
l3 = [{**u, **v} for u, v in sortedZipLongest[l1, l2, key="index", fillvalue={}]]
print[l3]
#[{'index': 0, 'green': 'ham'},
# {'index': 1, 'b': 2, 'c': 4},
# {'index': 2, 'b': 3, 'c': 5},
# {'index': 3, 'green': 'eggs'},
# {'index': 4, 'b': 4, 'green': 'ham'}]
Whereas original method would produce the incorrect answer:
l3 = [{**u, **v} for u, v in zip_longest[l1, l2, fillvalue={}]]
print[l3]
#[{'index': 1, 'b': 2, 'c': 4},
# {'index': 2, 'b': 3, 'c': 5},
# {'index': 0, 'green': 'ham'},
# {'index': 4, 'b': 4, 'green': 'ham'}]
View Discussion
Improve Article
Save Article
View Discussion
Improve Article
Save Article
Given two list of dictionaries, the task is to merge these two lists of dictionaries based on some value.
Method #1: Using
defaultdict
and extend
to merge two list of dictionaries based on school_id.
from
collections
import
defaultdict
Input1
=
[{
'roll_no'
: [
'123445'
,
'1212'
],
'school_id'
:
1
},
{
'roll_no'
: [
'HA-4848231'
],
'school_id'
:
2
}]
Input2
=
[{
'roll_no'
: [
'473427'
],
'school_id'
:
2
},
{
'roll_no'
: [
'092112'
],
'school_id'
:
5
}]
temp
=
defaultdict[
list
]
for
elem
in
Input1:
temp[elem[
'school_id'
]].extend[elem[
'roll_no'
]]
for
elem
in
Input2:
temp[elem[
'school_id'
]].extend[elem[
'roll_no'
]]
Output
=
[{
"roll_no"
:y,
"school_id"
:x}
for
x, y
in
temp.items[]]
print
[Output]
Output:
[{‘school_id’: 1, ‘roll_no’: [‘123445’, ‘1212’]}, {‘school_id’: 2, ‘roll_no’: [‘HA-4848231’, ‘473427’]}, {‘school_id’: 5, ‘roll_no’: [‘092112’]}]
Method #2: Using extend[]
only.
Input1
=
[{
'roll_no'
: [
'123445'
,
'1212'
],
'school_id'
:
1
},
{
'roll_no'
: [
'HA-4848231'
],
'school_id'
:
2
}]
Input2
=
[{
'roll_no'
: [
'473427'
],
'school_id'
:
2
},
{
'roll_no'
: [
'092112'
],
'school_id'
:
5
}]
for
elm2
in
Input2:
for
elm1
in
Input1:
if
elm2[
'school_id'
]
=
=
elm1[
'school_id'
]:
elm1[
'roll_no'
].extend[elm2[
'roll_no'
]]
break
else
:
Input1.append[elm2]
print
[Input1]
Output:
[{‘school_id’: 1, ‘roll_no’: [‘123445’, ‘1212’]}, {‘school_id’: 2, ‘roll_no’: [‘HA-4848231’, ‘473427’]}, {‘school_id’: 5, ‘roll_no’: [‘092112’]}]