我想在不知道確切位置的情況下獲取嵌套 json 檔案中特定鍵的值。所以基本上查看所有鍵(和嵌套鍵)直到找到匹配項,然后回傳字典 {match: "value"} Nested json_data:
{
"$id": "1",
"DataChangedEntry": {
"$id": "2",
"PathProperty": "/",
"Metadata": null,
"PreviousValue": null,
"CurrentValue": {
"CosewicWsRefId": {
"Value": "QkNlrjq2HL9bhTQqU8-qH"
},
"Date": {
"Value": "2022-05-20T00:00:00Z"
},
"YearSentToMinister": {
"Value": "0001-01-01T00:00:00"
},
"DateSentToMinister": {
"Value": "0001-01-01T00:00:00"
},
"Order": null,
"Type": {
"Value": "REGULAR"
},
"ReportType": {
"Value": "NEW"
},
"Stage": {
"Value": "ASSESSED"
},
"State": {
"Value": "PUBLISHED"
},
"StatusAndCriteria": {
"Status": {
"Value": "EXTINCT"
},
"StatusComment": {
"EnglishText": null,
"FrenchText": null
},
"StatusChange": {
"Value": "NOT_INITIALIZED"
},
"StatusCriteria": {
"EnglishText": null,
"FrenchText": null
},
"ApplicabilityOfCriteria": {
"ApplicabilityCriteriaList": []
}
},
"Designation": null,
"Note": null,
"DomainEvents": [],
"Version": {
"Value": 1651756761385.1248
},
"Id": {
"Value": "3z3XlCkaXY9xinAbK5PrU"
},
"CreatedAt": {
"Value": 1651756761384
},
"ModifiedAt": {
"Value": 1651756785274
},
"CreatedBy": {
"Value": "G@a"
},
"ModifiedBy": {
"Value": "G@a"
}
}
},
"EventAction": "Create",
"EventDataChange": {
"$ref": "2"
},
"CorrelationId": "3z3XlCkaXY9xinAbK5PrU",
"EventId": "WGxlewsUAHayLHZ2LHvFk",
"EventTimeUtc": "2022-05-06T13:15:31.7463355Z",
"EventDataVersion": "1.0.0",
"EventType": "AssessmentCreatedInfrastructure"
}
期望的回傳值是來自 json_data["DataChangedEntry"]["CurrentValue"]["Date"]["Value"] 的值:
"2022-05-20T00:00:00Z"
到目前為止,我已經嘗試了一個遞回函式,但它一直回傳None:
match_dict = {}
def recursive_json(data,attr,m_dict):
for k,v in data.items():
if k == attr:
for k2,v2 in v.items():
m_dict = {attr, v2}
print('IF: ',m_dict)
return m_dict
elif isinstance(v,dict):
return recursive_json(v,attr,m_dict)
print('RETURN: ',recursive_json(json_data, "Date", match_dict))
輸出:
RETURN: None
我嘗試洗掉第二return條陳述句,它現在在函式中列印我想要的值,但仍然回傳None:
match_dict = {}
def recursive_json(data,attr,m_dict):
for k,v in data.items():
if k == attr:
for k2,v2 in v.items():
m_dict = {attr, v2}
print('IF: ',m_dict)
return m_dict
elif isinstance(v,dict):
recursive_json(v,attr,m_dict)
print('RETURN: ',recursive_json(json_data, "Date", match_dict))
輸出:
IF: {'Date', '2022-05-20T00:00:00Z'}
RETURN: None
我不明白為什么它不斷回傳None。有沒有更好的方法來回傳我想要的值?
uj5u.com熱心網友回復:
潛在的問題是:我們如何在一個回圈中進行多次遞回呼叫,return如果其中任何一個回傳有用的東西,則遞回結果,否則失敗?
如果我們盲目地return進入回圈,那么只能進行一次遞回呼叫。無論它回傳什么,都會在這個級別回傳。如果它沒有找到有用的結果,我們就得不到有用的結果。
如果我們一味地不在回圈內回傳,那么回傳的值就無關緊要了。當前呼叫中沒有使用它們,所以我們將完成回圈,進行所有遞回呼叫,到達函式的末尾......因此隱式回傳None。
當然,解決這個問題的方法是檢查遞回呼叫是否回傳了有用的東西。如果是這樣,我們可以回傳它;否則,我們繼續前進。如果我們到達終點,那么我們會發出信號,表明我們找不到任何有用的東西——這樣,如果我們被遞回呼叫,呼叫者可以做正確的事情。
假設這None不是一個“有用的”值,我們自然可以將其用作信號。我們甚至不必在最后顯式地回傳它。
在修正了一些其他的錯別字之后(我們不應該覆寫全域內置dict名稱,而且無論如何我們不需要命名我們在開始時傳入的dict,并且引數應該是m_dict在我們制作時正確定義的遞回呼叫),我們得到:
def recursive_json(data, attr, m_dict):
for k,v in data.items():
if k == attr:
for k2,v2 in v.items():
m_dict = {attr, v2}
print('IF: ', m_dict)
return m_dict
elif isinstance(v,dict):
result = recursive_json(v, attr, m_dict)
if result:
return result
# call it:
recursive_json(json_data, "Date", {})
我們可以看到列印了除錯跟蹤,并且也回傳了值。
讓我們稍微改進一下:
首先,內部for k2,v2 in v.items():回圈沒有任何意義。同樣,我們每次呼叫只能return執行一次,因此這將跳過第一個之后的字典中的任何值。直接回傳我們會得到更好的服務v。此外,該m_dict引數實際上并不能幫助實作邏輯;我們不會在呼叫之間修改它。使用 a 作為我們的回傳值是沒有意義的set,因為它基本上是無序的;我們關心這里的順序。最后,我們不再需要除錯跟蹤。這給了我們:
def recursive_json(data, attr):
for k, v in data.items():
if k == attr:
return attr, v
elif isinstance(v,dict):
result = recursive_json(v, attr)
if result:
return result
為了更漂亮,我們可以將基本案例與遞回案例分開,并為每個案例使用更優雅的工具。要檢查是否有任何鍵匹配,我們可以簡單地檢查in操作員。要遞回并回傳第一個富有成效的結果,內置next函式很有用。我們得到:
def recursive_json(data, attr):
if not isinstance(data, dict):
# reached a leaf, can't search in here.
return None
if attr in data:
return k, data[k]
candidates = (recursive_json(v, attr) for v in data.values())
try:
# the first non-None candidate, if any.
return next(c for c in candidates if c is not None)
except StopIteration:
return None # all candidates were None.
uj5u.com熱心網友回復:
看起來你正在嘗試寫這樣的東西:
from json import loads
from typing import Any
test_json = """
{
"a": {
"b": {
"value": 1
}
},
"b": {
"value": 2
},
"c": {
"b": {
"value": 3
},
"c": {
"value": 4
}
},
"d": {}
}
"""
json_data = loads(test_json)
def find_value(data: dict, attr: str, depth_first: bool=True) -> (bool, Any):
# assumes data is a dict, with 'value' attributes for the attr to be found
# returns [whether value was found]: bool, [actual value]: Any
for k, v in data.items():
if k == attr and 'value' in v:
return True, v['value']
elif depth_first and isinstance(v, dict):
if (t := find_value(v, attr, depth_first))[0]:
return t
if not depth_first:
for _, v in data.items():
if isinstance(v, dict) and (t := find_value(v, attr, depth_first))[0]:
return t
return False, None
# returns True, 1 - first 'b' with a 'value', depth-first
print(find_value(json_data, 'b'))
# returns True, 2 - first 'b' with a 'value', breadth-first
print(find_value(json_data, 'b', False))
# returns True, 4 - first 'c' with a 'value' - the 'c' at the root level has no 'value'
print(find_value(json_data, 'c'))
# returns False, None - no 'd' with a value
print(find_value(json_data, 'd'))
# returns False, None - no 'e' in data
print(find_value(json_data, 'e'))
您自己的函式可以回傳None,因為您實際上并沒有回傳遞回呼叫將回傳的值。函式的默認回傳值為None.
但是,您的代碼也沒有考慮到找不到任何東西的情況。
(注意:此解決方案僅適用于 Python 3.8 或更高版本,因為它使用了海象運算子:=- 當然,不寫它并不難,但這留給讀者作為練習
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/484151.html
標籤:Python
上一篇:如何將中心的邊框影片與文本對齊
