Reputation:
I have found no answer to my specific issue. The standard way I am searching nested dicts with for loops is not so suitable for me, because I have a variety of different structures of those dicts (all in this one dict!). Some dicts go deeper than other and also have different key names.
So what I like to have is something similiar to SQL. So for the fist key I want to extract the value of a specific sub key within this dict structure without knowing its structure (so to know where and if this key exists).
I need something like:
data=nested_dict
[value for key, value in data.items() WHERE key.name="name"]
Or another way would be just to extract the "position" of a key (the level)?
Upvotes: 0
Views: 2523
Reputation: 124
Your example code does not quite seem to match your worded description of what you want to achieve. Anyway, the code you wrote is almost valid. The Python analogue of the SQL WHERE-statement in this case would be list comprehension with an if-statement:
data = {
"key_1": {
"name": "Alice",
"age": 21
},
"key_2": {
"name": "Bob",
"hobbies": ["cryptography", "tennis"]
}
}
# Extract the first value in data that contains a key 'name' with the value 'Bob'
value = [v for v in data.values() if v["name"] == "Bob"][0]
assert value == {"name": "Bob", "hobbies": ["cryptography", "tennis"]}
Of course this will raise a KeyError exception, if data contained any sub-dict that has no key "name". To deal with that just use:
data_with_name = [v for v in data.values() if "name" in v]
value = [v for v in data_with_name.values() if v["name"] == "Bob"][0]
This code might still raise a TypeError exception, if data contained values that are not sub-dicts, so you might want to use:
data_with_name = [v for v in data.values() if isinstance(v, dict) and "name" in v]
You can also filter out all sub-dicts that meet a certain condition, using dict comprehension:
data_called_bob = {k: v for k, v in data_with_name.items() if v["name"] == "Bob"}
If Bob might be hidden deep inside your nested dict, and you want to extract the first sub-dict that contains the k-v-pair ("name", "Bob") on an arbitrarily deep level, use recursion:
def find_sub_dict(data, key, value):
if isinstance(data, dict) and key in data and data[key] == value:
return data
elif not isinstance(data, dict):
return None
else:
for v in data.values():
result = find_sub_dict(v, key, value)
if result is not None:
return result
value = find_sub_dict(data, "name", "Bob")
I hope I could help you. :)
Cheers, Silas
Upvotes: 2