[英]How to get keys from nested dictionary in a pythonic way
I have some items in a nested dictionary and I need to match if any word in a sentence matches the values in the dictionary.我在嵌套字典中有一些项目,如果句子中的任何单词与字典中的值匹配,我需要匹配。 If it does, it returns all the keys from the nested list.
如果是,则返回嵌套列表中的所有键。
What I have tried so far:到目前为止我已经尝试过:
animals = {
'vertebrates': {
'warm_blooded': {
'mammals': ['bear', 'tiger', 'lion'],
'birds': ['eagle', 'ostrich', 'duck']
},
'cold_blooded': {
'reptiles': ['turtle', 'crocodile'],
'amphibians': ['frog', 'toad']
}
}
}
line = 'lions live in the savanna.'
for key1, value1 in animals.items():
for key2, value2 in value1.items():
for key3, value3 in value2.items():
if any(word in line for word in value3):
print ([key1, key2, key3])
>>> ['vertebrates', 'warm_blooded', 'mammals']
Currently it does what I need.目前它可以满足我的需要。 What I want to know if there's a way to re-write this code in a more pythonic (elegant) way as this for loop might get longer if there's more levels in the dictionary to to tranverse through.
我想知道是否有办法以更 Pythonic(优雅)的方式重写此代码,因为如果字典中有更多级别可以遍历,则 for 循环可能会变得更长。
Here is a simple method using recursion which keeps track of keys along the way.这是一个使用递归的简单方法,它沿途跟踪键。 This should illustrate how you would do this for arbitrary lengths.
这应该说明您将如何针对任意长度执行此操作。
def key_match(data, to_match, found):
for k, v in data.items():
if isinstance(v, dict):
key_match(v, to_match, found + [k])
else:
if any(word in line for word in v):
print(found + [k])
found = []
key_match(animals, line, found)
['vertebrates', 'warm_blooded', 'mammals']
Could make a recursive function that keeps track of the path, and prints the path when an animal is found in line
.可以创建一个递归的 function 来跟踪路径,并在找到动物
line
打印路径。
def search_animals_rec(animals, line, path):
for k, v in animals.items():
if isinstance(v, dict):
search_animals_rec(v, line, path + [k])
elif isinstance(v, list):
for animal in v:
if animal in line:
print(path + [k])
search_animals_rec(animals, line, [])
Or using any()
:或使用
any()
:
def search_animals_rec(animals, line, path):
for k, v in animals.items():
if isinstance(v, dict):
search_animals_rec(v, line, path + [k])
elif isinstance(v, list):
if any(animal in line for animal in v):
print(path + [k])
Output: Output:
['vertebrates', 'warm_blooded', 'mammals']
Note: The above obviously doesn't handle all edge cases, but it shows how you could approach a recursive brute force solution.注意:以上显然不能处理所有边缘情况,但它显示了如何处理递归蛮力解决方案。 A more efficient solution would be build a reverse index as pointed out in the comments.
如评论中所指出的,更有效的解决方案是构建反向索引。
i like the flatten-dict module, might come in handy in a few operations:我喜欢flatten-dict模块,可能会在一些操作中派上用场:
from flatten_dict import flatten
flat = flatten(animals)
print(flat)
{('vertebrates', 'warm_blooded', 'mammals'): ['bear', 'tiger', 'lion'],
('vertebrates', 'warm_blooded', 'birds'): ['eagle', 'ostrich', 'duck'],
('vertebrates', 'cold_blooded', 'reptiles'): ['turtle', 'crocodile'],
('vertebrates', 'cold_blooded', 'amphibians'): ['frog', 'toad']}
You wont find lions in any of the values, but take away the 's' and you'll find lion你不会在任何值中找到狮子,但去掉's',你会发现狮子
line = 'lion live in the savanna.'
#used a set to avoid duplication
words = set(line.strip('.').split())
print(words)
{'in', 'lion', 'live', 'savanna', 'the'}
[key for word in words for key,value in flat.items() if word in value ]
[('vertebrates', 'warm_blooded', 'mammals')]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.