In a given Dictionary, I need to find a nested Dictionary ([String : Any]
) for a given key.
The general structure of the Dictionary (e.g. nesting levels, value types) is unknown and given dynamically. [1]
Inside of this sub-Dictionary, there is a given value for the key "value" (don't ask) which needs to be fetched.
Here's an example:
let theDictionary: [String : Any] =
[ "rootKey" :
[ "child1Key" : "child1Value",
"child2Key" : "child2Value",
"child3Key" :
[ "child3SubChild1Key" : "child3SubChild1Value",
"child3SubChild2Key" :
[ "comment" : "child3SubChild2Comment",
"value" : "child3SubChild2Value" ]
],
"child4Key" :
[ "child4SubChild1Key" : "child4SubChild1Value",
"child4SubChild2Key" : "child4SubChild2Value",
"child4SubChild3Key" :
[ "child4SubChild3SubChild1Key" :
[ "value" : "child4SubChild3SubChild1Value",
"comment" : "child4SubChild3SubChild1Comment" ]
]
]
]
]
With brute force and pseudo memoization, I managed to hack a function together that iterates through the entire Dictionary and fetches the value for a given key:
func dictionaryFind(_ needle: String, searchDictionary: Dictionary<String, Any>) -> String? {
var theNeedleDictionary = Dictionary<String, Any>()
func recurseDictionary(_ needle: String, theDictionary: Dictionary<String, Any>) -> Dictionary<String, Any> {
var returnValue = Dictionary<String, Any>()
for (key, value) in theDictionary {
if value is Dictionary<String, Any> {
if key == needle {
returnValue = value as! Dictionary<String, Any>
theNeedleDictionary = returnValue
break
} else {
returnValue = recurseDictionary(needle, theDictionary: value as! Dictionary<String, Any>)
}
}
}
return returnValue
}
// Result not used
_ = recurseDictionary(needle, theDictionary: searchDictionary)
if let value = theNeedleDictionary["value"] as? String {
return value
}
return nil
}
This works so far. (For your playground testing pleasure:
let theResult1 = dictionaryFind("child3SubChild2Key", searchDictionary: theDictionary)
print("And the result for child3SubChild2Key is: \(String(describing: theResult1!))")
let theResult2 = dictionaryFind("child4SubChild3SubChild1Key", searchDictionary: theDictionary)
print("And the result for child4SubChild3SubChild1Key is: \(String(describing: theResult2!))")
let theResult3 = dictionaryFind("child4Key", searchDictionary: theDictionary)
print("And the result for child4Key is: \(String(describing: theResult3))")
).
My question here:
What would be a more clean, concise, "swifty", way to iterate through the Dictionary and - especially - break completely out of the routine as soon the needed key has been found?
Could a solution even be achieved using a Dictionary extension?
Thanks all!
[1] A KeyPath as described in Remove nested key from dictionary therefor isn't feasible.