我撰寫了一個函式,它應該能夠使用 DFS 搜索嵌套字典以查找特定值。遞回元素似乎作業正常,但是,當基本情況應該回傳 True 時,它??根本就沒有。
obj = {'a': [{'c':'d'}, {'e':'f'}],
'b': [{'g':'h'}, {'i':'j'}]}
def obj_dfs(obj, target):
if type(obj) == dict:
for key, val in obj.items():
obj_dfs(key, target)
obj_dfs(val, target)
elif type(obj) in (list, tuple):
for elem in obj:
obj_dfs(elem, target)
else:
if obj == target:
print(f"{obj} == {target}")
return True
else:
print(f"{obj} != {target}")
return False
obj_dfs(obj, 'j')
和結果。如您所見,標準輸出“i==i”表明該元素已正確評估,但 return True 陳述句未按預期運行。我已經驗證,如果我打電話obj_dfs(obj, 'j'),那會遇到同樣的錯誤。
a != j
c != j
d != j
e != j
f != j
b != j
g != j
h != j
i != j
j == j
False
為什么是這樣?我該如何解決這個問題?
uj5u.com熱心網友回復:
正如評論所指出的,您需要回傳遞回呼叫的結果。由于您只是在尋找真/假匹配,因此您可以將遞回呼叫傳遞到any()其中,True如果存在匹配則將提前退出。基本情況可以簡單地是是否obj == target。
obj = {'a': [{'c':'d'}, {'e':'f'}],
'b': [{'g':'h'}, {'i':'j'}]}
def obj_dfs(obj, target):
if obj == target:
return True
if isinstance(obj, dict):
return any(obj_dfs(v, target) for v in obj.items())
elif isinstance(obj, (list, tuple)):
return any(obj_dfs(l, target) for l in obj)
return False
obj_dfs(obj, 'i'), obj_dfs(obj, 'j'), obj_dfs(obj, 'd'), obj_dfs(obj, 'x')
# (True, True, True, False)
這允許三個簡單的塊。請注意,我們正在檢查最后一個中的atuple和 a 。這使您可以簡單地傳入 dict ,而不是獨立地回圈鍵和值。listisinstanceitem()
添加 aprint(obj)作為函式的第一行將顯示您遍歷資料的順序。例如obj_dfs(obj, 'j')將列印:
{'a': [{'c': 'd'}, {'e': 'f'}], 'b': [{'g': 'h'}, {'i': 'j'}]}
('a', [{'c': 'd'}, {'e': 'f'}])
a
[{'c': 'd'}, {'e': 'f'}]
{'c': 'd'}
('c', 'd')
c
d
{'e': 'f'}
('e', 'f')
e
f
('b', [{'g': 'h'}, {'i': 'j'}])
b
[{'g': 'h'}, {'i': 'j'}]
{'g': 'h'}
('g', 'h')
g
h
{'i': 'j'}
('i', 'j')
i
j
uj5u.com熱心網友回復:
我對您的代碼進行了一些編輯
obj = {'a': [{'c':'d'}, {'e':'f'}],
'b': [{'g':'h'}, {'i':'j'}]}
def obj_dfs(obj, target):
if type(obj) == dict:
for key, val in obj.items():
if(key==target):
return val
else:
result=obj_dfs(val, target)
if result!=None: return result
elif type(obj) in (list, tuple):
for elem in obj:
result=obj_dfs(elem, target)
if result!=None: return result
else:
if obj==target: return True
print(obj_dfs(obj, 'i'))
我不知道你為什么只回傳true而不是值,所以我說如果它是一個字典鍵,它會回傳值,而不是回傳true,以表明它被找到
uj5u.com熱心網友回復:
擴展我的評論,試試這個,我們將回傳值傳遞到鏈上,True如果孩子回傳,則總是回傳True:
obj = {'a': [{'c':'d'}, {'e':'f'}],
'b': [{'g':'h'}, {'i':'j'}]}
obj2 = {'a': [{'c':'d'}, {'e':'f'}],
'b': [{'g':'h'}, {'g':'j'}]}
def obj_dfs(obj, target):
if type(obj) == dict:
for key, val in obj.items():
keyret = obj_dfs(key, target)
valueret = obj_dfs(val, target)
if keyret is True or valueret is True:
return True
else:
return False
elif type(obj) in (list, tuple):
rets = []
for elem in obj:
rets.append(obj_dfs(elem, target))
if True in rets:
return True
else:
return False
else:
if obj == target:
print(f"{obj} == {target}")
return True
else:
print(f"{obj} != {target}")
return False
print(obj_dfs(obj, 'i'))
print(obj_dfs(obj2, 'i'))
uj5u.com熱心網友回復:
遞回是一種函式式遺產,因此將其與函式式風格一起使用會產生最佳結果。這意味著解耦關注點并將副作用推到程式的邊緣。obj_dfs執行深度優先遍歷并混合搜索邏輯。并且出于除錯目的,包括一個print副作用。
分解導致函式更容易在我們程式的各個部分中撰寫、測驗和重用。我們將從dfs遍歷的泛型開始 -
def dfs(t, path = []):
if isinstance(t, dict):
for key, val in t.items():
yield from dfs(val, [*path, key])
elif isinstance(t, (list, tuple)):
for key, val in enumerate(t):
yield from dfs(val, [*path, key])
else:
yield path, t
obj = {'a': [{'c':'d'}, {'e':'f'}],
'b': [{'g':'h'}, {'i':'j'}]}
for path, val in dfs(obj):
print(path, val) # side effect decided by caller
['a', 0, 'c'] d
['a', 1, 'e'] f
['b', 0, 'g'] h
['b', 1, 'i'] j
此處建議的解決方案和其他答案消除了鍵和值之間的語意差異,對target. 像我們上面寫dfs的那樣,我們可以知道obj匹配的部分。
| 鑰匙 | 價值觀 |
|---|---|
| ['a', 0, 'c'] | d |
| ['a', 1, 'e'] | F |
| ['b', 0, 'g'] | H |
| ['b', 1, 'i'] | j |
has_value并且has_key很容易定義為dfs-
def has_value(t, target):
for path, val in dfs(t):
if val == target:
return True
return False
def has_key(t, target):
for path, val in dfs(t):
if target in path:
return True
return False
print(has_value(obj, "j")) # True
print(has_key(obj, "j")) # False
print(has_value(obj, "i")) # False
print(has_key(obj, "i")) # True
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/479598.html
上一篇:范圍內的最大總和元素
