I call an API which returns me some lists of dictionaries that I want to search for their common id
and combine the data. The returned data has the shape:
LEVELS = ["wind", "water", "ice", "earth"]
A = [{"id": 4, "active": True},
{"id": 5, "active": True},
{"id": 7, "active": False}]
B = [{"id": 5, "status": "red", "level": "water"},
{"id": 4, "status": "green", "level": "wind"},
{"id": 7, "status": "yellow", "level": "wind"}]
C = [{"id": 7, "value": 5},
{"id": 4, "value": None},
{"id": 5, "value": 8}]
I try iterating / combining with a multitude of for loops:
for level in LEVELS:
for b in B:
if b["level"] == level:
for c in C:
for a in A:
if a["id"] == b["id"] and b["id"] == c["id"]:
print(f"""Level: {level} - {c["id"]} - {a["active"]} - {b["status"]} - {c["value"]}""")
Eventually this works, but only for small numbers. My question is how to do this for larger lists with many items each. For simplicity: All Ids will be the same in all the items and wont appear multiple times.
Level: wind - 4 - True - green - None
Level: wind - 7 - False - yellow - 5
Level: water - 5 - True - red - 8
CodePudding user response:
Since you want to combine the dictionaries based on id
, you can create a dict to contain these combined dicts instead of a list.
First, create the lookup_dict
from the items in B
. The key will be the id
of each item, and the value
will be the item itself
lookup_dict = dict()
for item in B:
item_id = item["id"]
lookup_dict[item_id] = item
Next, update these dicts with the dicts in A
and C
.
for item in A:
item_id = item["id"]
if item_id in lookup_dict:
lookup_dict[item_id].update(item)
else:
print(f"ID {item_id} did not exist in list B")
Do the same for item in C
.
Now, lookup_dict
looks like this:
{
5: {'id': 5,
'status': 'red',
'level': 'water',
'active': True,
'value': 8},
4: {'id': 4,
'status': 'green',
'level': 'wind',
'active': True,
'value': None},
7: {'id': 7,
'status': 'yellow',
'level': 'wind',
'active': False,
'value': 5}
}
Printing is fairly straightforward:
for item in lookup_dict.values():
print(f'Level: {item["level"]} - {item["id"]} - {item["active"]} - {item["status"]} - {item["value"]}')
which gives:
Level: water - 5 - True - red - 8
Level: wind - 4 - True - green - None
Level: wind - 7 - False - yellow - 5
CodePudding user response:
You can combine those dictionaries using update()
. In this case, I made it with B
:
Edit: As someone correctly pointed out, all the list must be sorted beforehand otherwise it may (probably will) return wrong results.
def sort_by_id(x):
return x["id"]
A.sort(key=sort_by_id)
B.sort(key=sort_by_id)
C.sort(key=sort_by_id)
for i, b in enumerate(B):
b.update(A[i].items())
b.update(C[i].items())
print(B)
Where now B
has the following values:
[{'id': 7, 'status': 'red', 'level': 'water', 'active': True, 'value': 5},
{'id': 4, 'status': 'green', 'level': 'wind', 'active': True, 'value': None},
{'id': 5, 'status': 'yellow', 'level': 'wind', 'active': False, 'value': 8}]
Then you can format a string to show the values as you please:
# assuming A, B and C were sorted
for i, b in enumerate(B):
b.update(A[i].items())
b.update(C[i].items())
print(f"Level: {b['level']} - {b['active']} - {b['status']} - {b['value']}")
The result would be:
Level: water - True - red - 5
Level: wind - True - green - None
Level: wind - False - yellow - 8
It is obvious that the error management side of things is missing in this implementation so you would need to add that code to make it safe to run.