您如何利用 Swift 功能来重构此递归函数?

How can you leverage Swift features to refactor this recursive function?

我一直在研究递归函数,以从表示为 NSDictionary 的 JSON 数据中提取字符串值。该函数允许您这样做:

if let value = extractFromNestedDictionary(["fee" : ["fi" : ["fo" : "fum"]]], withKeys: ["fee", "fi", "fo"]) {
    println("\(value) is the value after traversing fee-fi-fo");
}

函数实现如下所示:

// Recursively retrieves the nested dictionaries for each key in `keys`,
// until the value for the last key is retrieved, which is returned as a String?
func extractFromNestedDictionary(dictionary: NSDictionary, withKeys keys: [String]) -> String? {
    if keys.isEmpty { return nil }
    let head = keys[0]
    if let result: AnyObject = dictionary[head] {
        if keys.count == 1 {
            return result as? String
        } else {
            let tail: [String] = Array(keys[1..<keys.count])
            if let result = result as? NSDictionary {
                return extractFromNestedDictionary(result, withKeys: tail)
            } else {
                return nil
            }
        }
    } else {
        return nil
    }
}

在 Swift 1.2/2.x 中是否有一些与可选绑定相关的语法特征可以:

我本来不想在没有你先尝试的情况下就成功的,但我还是做了,因为我喜欢 Swift 并且很开心:

func extractFromNestedDictionary(dictionary: [NSObject : AnyObject], var withKeys keys: [String]) -> String? {
    if let head = keys.first, result = dictionary[head] {
        if keys.count == 1 {
            return result as? String
        } else if let result = result as? [NSObject : AnyObject] {
            keys.removeAtIndex(0)
            return extractFromNestedDictionary(result, withKeys: keys)
        }
    }
    return nil
}


extractFromNestedDictionary(["A" : ["B" : ["C" : "D"]]], withKeys: ["A", "B", "C"])

一些注意事项:

  • 尽量避免使用 NSDictionary 并使用 [NSObject : AnyObject] 代替,它无论如何都可以桥接到 NSDictionary 并且更 Swifty
  • 问问题的时候,试着举一个比你在那里做的更好的例子,从你的例子中我无法知道你到底想做什么。

这是我想出的最好的...

func extractFromNestedDictionary(dictionary: [NSObject : AnyObject], withKeys keys: [String]) -> String? {
    if let head = keys.first,
        result = dictionary[head] as? String
        where keys.count == 1 {
            return result
    } else if let head = keys.first,
        result = dictionary[head] as? [NSObject : AnyObject] {
            return extractFromNestedDictionary(result, withKeys: Array(keys[1..<keys.count]))
    }
    return nil
}

您可以在 keys 数组上使用 reduce 而不是递归 遍历字典:

func extractFromNestedDictionary(dictionary: NSDictionary, withKeys keys: [String]) -> String? {

    return reduce(keys, dictionary as AnyObject?) {
        ([=10=] as? NSDictionary)?[] 
    } as? String
}

在闭包内部,[=13=] 是当前级别的(可选)对象,</code> 当前密钥。闭包return是下一层的对象 如果 <code>[=13=] 是一个字典 and 有当前键的值, nil 否则。 reduce() 的 return 值是 最后一层的对象或 nil.

我知道这并没有严格回答问题。但是你可以只使用 valueForKeypath:

let fum = dict.valueForKeyPath("fee.fi.fo")