如何利用Swift功能重构这个递归函数?

时间:2015-07-11 19:21:16

标签: swift recursion nsdictionary

我一直在研究递归函数,从表示为NSDictionary的JSON数据中提取String值。该功能允许您执行此操作:

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中的可选绑定相关的语法功能可以:

  • 使这个功能更简洁
  • 少用if嵌套

4 个答案:

答案 0 :(得分:3)

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

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

    return reduce(keys, dictionary as AnyObject?) {
        ($0 as? NSDictionary)?[$1] 
    } as? String
}

在闭包内,$0是当前级别的{可选]对象$1 当前的关键。闭包返回下一级别的对象 如果$0是字典具有当前密钥的值, 否则nil。那么reduce()的返回值就是 最后一级的对象或nil

答案 1 :(得分:1)

我原本不想在没有你先尝试的情况下做到这一点,但我仍然这样做,因为我喜欢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,而且更加快捷
  • 在提问时,尝试做一个比你在那里更好的例子,从你的例子我不知道你到底想做什么。

答案 2 :(得分:1)

我知道这并不是严格回答这个问题。但你可以使用valueForKeypath

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

答案 3 :(得分:0)

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

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
}