Home > database >  create dictionary from multiple (list of) directories based on key
create dictionary from multiple (list of) directories based on key

Time:09-23

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.

  • Related