Swift 4:在嵌套的动态字典中查找值<;字符串,任意>;递归地
在给定的字典中,我需要找到给定键的嵌套字典(Swift 4:在嵌套的动态字典中查找值<;字符串,任意>;递归地,swift,dictionary,recursion,closures,Swift,Dictionary,Recursion,Closures,在给定的字典中,我需要找到给定键的嵌套字典([String:Any]) 字典的一般结构(例如嵌套级别、值类型)未知且动态给定。[1] 在这个子字典中,需要获取的键“value”(不要问)有一个给定的值 下面是一个例子: let theDictionary: [String : Any] = [ "rootKey" : [ "child1Key" : "child1Value", "child2Key" : "child2Value", "child3Key"
[String:Any]
)
字典的一般结构(例如嵌套级别、值类型)未知且动态给定。[1]
在这个子字典中,需要获取的键“value”(不要问)有一个给定的值
下面是一个例子:
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" ]
]
]
]
]
通过暴力和伪记忆,我成功地破解了一个函数,该函数遍历整个字典并获取给定键的值:
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
}
)
我的问题是:
有什么更干净、简洁、“快速”的方法来迭代字典,尤其是在找到所需的键后,立即完全脱离常规
甚至可以使用字典扩展来实现解决方案吗
谢谢大家
[1] 中所述的密钥路径不可行。更紧凑的递归解决方案可能是:
func search(key:String, in dict:[String:Any], completion:((Any) -> ())) {
if let foundValue = dict[key] {
completion(foundValue)
} else {
dict.values.enumerated().forEach {
if let innerDict = $0.element as? [String:Any] {
search(key: key, in: innerDict, completion: completion)
}
}
}
}
用法是:
search(key: "child3SubChild2Key", in: theDictionary, completion: { print($0) })
其中:
["comment": "child3SubChild2Comment", "value": "child3SubChild2Subchild1Value"]
或者,如果不想使用闭包,可以使用以下选项:
extension Dictionary {
func search(key:String, in dict:[String:Any] = [:]) -> Any? {
guard var currDict = self as? [String : Any] else { return nil }
currDict = !dict.isEmpty ? dict : currDict
if let foundValue = currDict[key] {
return foundValue
} else {
for val in currDict.values {
if let innerDict = val as? [String:Any], let result = search(key: key, in: innerDict) {
return result
}
}
return nil
}
}
}
用途是:
search(key: "child3SubChild2Key", in: theDictionary, completion: { print($0) })
let result = theDictionary.search(key: "child4SubChild3SubChild1Key")
print(result) // ["comment": "child4SubChild3SubChild1Comment", "value": "child4SubChild3SubChild1Value"]
以下扩展可用于在嵌套字典中查找键的值,其中不同的级别可以包含与不同值关联的相同键
扩展字典,其中Key==String{
func find(ukey:String)->[T]{
变量键:[T]=[]
如果let value=self[key]as?T{
keys.append(值)
}
self.values.compactMap({$0作为?[String:Any]}).forEach({
key.append(contentsOf:$0.find(key))
})
返回键
}
}
非常感谢Andrea!读起来更清晰。我测试了您的代码,它在打印子字典内容方面运行良好。这里的问题是,我不知道如何使用传递内部字典的完成处理程序,以便在不传递返回值的情况下提取值(最好使用下标符号)。如果你能扩展你的用法示例,这样至少子字典可以被进一步使用,那就太好了。@andrea mugnani为不清楚道歉。我最喜欢的是Dictionary的一个扩展函数,我只需要说“让myResultValue=myDictionary.getNestedValue(forKey:“mySpecialKey”)”。这应该递归地搜索字典。如果它找到字典中的键,它应该获取底层键“value”的值(我知道,命名混乱)。但是你的搜索功能可以让我找回以前使用过的字典,我只是不知道如何打破这里的完成处理程序:-嗨@andrea Mugnani-我真的很感谢你的工作-非常感谢。在操场上使用上面给出的字典和以下代码尝试了它:“let result=theDictionary.search(key:“child4SubChild3SubChild1Key”)print((String(description:result))”),但结果为零,而应该是“[”value:“child4SubChild3SubChild1Value”,“comment:“child4SubChild3SubChild1Comment”]”—在测试打印的情况下,但就API而言,它应该是子字典。抱歉这么不清楚。嗨@andrea Mugnani-在操场上,我收到一个错误“错误:执行被中断,原因:EXC_坏访问(代码=EXC_I386_GPFLT)。进程被留在中断的位置,请使用“thread return-x”返回到表达式求值之前的状态在执行第一个解决方案代码时,无论出于何种原因,我以前都没有看到。只是想让你知道:)嗨@andrea Mugnani-非常感谢-这一切都如期而至。要找到最终值,我只需要包装搜索扩展函数func。它现在清晰、简洁,而且由于初始的防护条件,看起来也相当健壮。我很高兴地接受这一有效的回答,并再次感谢您提供了这一软件工艺上的宝贵经验:)我想其他遇到这个问题的人也会喜欢您的代码!