Swift 3 - extend an Array of Dictionary<String, Any>

房东的猫 提交于 2019-12-10 18:28:17

问题


I have this array of dictionaries:

var dicts = [["key1": "value1", "key2": "value2"], ["key1": "value3", "key2": "value4"]]

How should I extend Array so that I have this function:

dicts.values(of: "key1") // result: ["value1", "value3"]

I try this:

extension Array where Iterator.Element == [String: Any] { // ERROR!

    func values(of key: String) -> [Any]? {
        var result: [Any]?
        for value in self {
            let val = value as! Dictionary<String, Any>
            for k in val.keys {
                if k == key {
                    if result == nil {
                        result = [Any]()
                    }
                    result?.append(val[k])
                    break
                }
            }
        }
        return result
    }
}

But I always have error marked at extension Array declaration:

error: same-type requirement makes generic parameter 'Element' non-generic

What should I do to fix this error?

Is it right to iterate Array with for value in self?

Thanks


回答1:


extension Sequence where Iterator.Element == [String: Any] {

    func values(of key: String) -> [Any]? {
        var result: [Any] = []
        for value in self {
            let val = value 
            for (k, v) in val {
                if k == key {
                    result.append(v)
                    break
                }
            }
        }
        return result.isEmpty ? nil : result
    }
}

var dicts: [[String: Any]] = [["key1": "value1", "key2": "value2"], ["key1": "value3", "key2": "value4"]]
dicts.values(of: "key1")   // ["value1", "value3"]

or shorter version:

extension Sequence where Iterator.Element == [String: Any] {

    func values(of key: String) -> [Any]? {
        let result: [Any] = reduce([]) { (result, dict) -> [Any] in
            var result = result
            result.append(dict.filter{ $0.key == key }.map{ $0.value })
            return result
        }
        return result.isEmpty ? nil : result
    }
}

var dicts: [[String: Any]] = [["key1": "value1", "key2": "value2"], ["key1": "value3", "key2": "value4"]]
dicts.values(of: "key1")

and without reduce functionality:

extension Sequence where Iterator.Element == [String: Any] {

    func values(of key: String) -> [Any]? {
        var result: [Any] = []
        forEach {
            result.append($0.filter{ $0.key == key }.map{ $0.value })
        }
        return result.isEmpty ? nil : result
    }
}

var dicts: [[String: Any]] = [["key1": "value1", "key2": "value2"], ["key1": "value3", "key2": "value4"]]
dicts.values(of: "key1")



回答2:


Consolidated solution with compactMap (flatMap in Swift 3) which filters nil values

let dicts : [[String:Any]] = [["key1": "value1", "key2": "value2"], ["key1": "value3", "key2": "value4"]]

extension Sequence where Iterator.Element == [String:Any] {

  func values(of key: String) -> [Any] {
    return self.compactMap {$0[key]}
  }
}

dicts.values(of:"key1")



回答3:


Thanks, @JMI, for your solution, which is very elegant.

I'd just like to add a little more details to your work:

extension Sequence where Iterator.Element == [String: Any] {
    func values(of key: String) -> [Any]? {
        var result = [Any]()
        forEach {
            let tmp = $0.filter{$0.key == key}.map{$0.value}
            if tmp.count > 0 {
                result.append(tmp[0])
            }
        }
        return result.isEmpty ? nil : result
    }
}

var dicts: [[String: Any]] = [["key1": "value1", "key2": "value2"], ["key1": "value3", "key2": "value4"]]

if let result = dicts.values(of: "key1") {
    for element in result {
        print("\(element) -> \(type(of: element))")
    }
}
else {
    print("no result")
}

Best,



来源:https://stackoverflow.com/questions/40107743/swift-3-extend-an-array-of-dictionarystring-any

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!