Swift 4:在嵌套的动态Dictionary< String,Any>中查找值递归地 [英] Swift 4: Find value in nested, dynamic Dictionary<String, Any> recursively

查看:398
本文介绍了Swift 4:在嵌套的动态Dictionary< String,Any>中查找值递归地的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在给定的字典中,我需要找到给定键的嵌套字典([String : Any]).

In a given Dictionary, I need to find a nested Dictionary ([String : Any]) for a given key.

字典的一般结构(例如嵌套级别,值类型)是未知的,并且是动态给出的. [1]

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.

这是一个例子:

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" ]
            ]
        ]
    ]
  ]

借助蛮力和伪记忆,我设法一起破解了一个功能,该功能遍历整个Dictionary并获取给定键的值:

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))")

).

我的问题在这里:

什么是更干净,简洁,敏捷"的方法来遍历字典,尤其是在找到所需的密钥后完全脱离常规?

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?

甚至可以使用Dictionary扩展实现解决方案吗?

Could a solution even be achieved using a Dictionary extension?

谢谢!

[1] 从字典中删除嵌套键中所述的KeyPath不存在不可行.

[1] A KeyPath as described in Remove nested key from dictionary therefor isn't feasible.

推荐答案

更紧凑的递归解决方案可能是:

A more compact recursive solution might be:

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"]


或者,如果您不想使用闭包,则可以使用以下内容:


alternatively, if you don't want to use closures, you might use the following:

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
        }
    }
}

用法是:

let result = theDictionary.search(key: "child4SubChild3SubChild1Key")
print(result) // ["comment": "child4SubChild3SubChild1Comment", "value": "child4SubChild3SubChild1Value"]

这篇关于Swift 4:在嵌套的动态Dictionary&lt; String,Any&gt;中查找值递归地的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆