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。它现在清晰、简洁,而且由于初始的防护条件,看起来也相当健壮。我很高兴地接受这一有效的回答,并再次感谢您提供了这一软件工艺上的宝贵经验:)我想其他遇到这个问题的人也会喜欢您的代码!