首页 文章

有没有一种将Array转换为Dictionary的声明方法?

提问于
浏览
31

我想从这个字符串数组中获取

let entries = ["x=5", "y=7", "z=10"]

对此

let keyValuePairs = ["x" : "5", "y" : "7", "z" : "10"]

我试图使用 map ,但问题似乎是字典中的键值对不是一个独特的类型,它实际上提供了一个转换函数,因为没有什么可以转换为 . 加 map 返回一个数组,所以这是不行的 .

有任何想法吗?

8 回答

  • 9

    好的答案已经 . 以下是集合类型扩展的另一种方法 . 您可以将任何集合类型转换为字典,数组或集合 .

    extension CollectionType {
        func map2Dict<K, V>(@noescape map: ((Self.Generator.Element) -> (K,    V)?))  -> [K: V] {
            var d = [K: V]()
            for e in self {
                if let kV = map(e) {
                    d[kV.0] = kV.1
                }
            }
    
            return d
        }
    
        func map2Array<T>(@noescape map: ((Self.Generator.Element) -> (T)?))  -> [T] {
            var a = [T]()
            for e in self {
                if let o = map(e) {
                    a.append(o)
                }
            }
    
            return a
        }
    
        func map2Set<T>(@noescape map: ((Self.Generator.Element) -> (T)?))  -> Set<T> {
            return Set(map2Array(map))
        }
     }
    

    这是示例用法 .

    let entries = ["x=5", "y=7", "z=10"]
    let dict:[String: String]  = entries.map2Dict({
    let components = $0.componentsSeparatedByString("=")
        return (components.first!, components.last!)
    })
    
    print("dict \(dict)")
    
  • 52

    Swift 4

    正如fl034所提到的,这可以通过Swift 4进行简化,其中错误检查版本如下所示:

    let foo = entries
        .map { $0.components(separatedBy: "=") }
        .reduce(into: [String:Int64]()) { dict, pair in
            if pair.count == 2, let value = Int64(pair[1]) {
                dict[pair[0]] = value
            }
        }
    

    如果您不希望值为Ints,则更简单:

    let foo = entries
        .map { $0.components(separatedBy: "=") }
        .reduce(into: [String:String]()) { dict, pair in
            if pair.count == 2 {
                dict[pair[0]] = pair[1]
            }
        }
    

    Older TL;DR

    减去错误检查,它看起来非常像:

    let foo = entries.map({ $0.componentsSeparatedByString("=") })
        .reduce([String:Int]()) { acc, comps in
            var ret = acc
            ret[comps[0]] = Int(comps[1])
            return ret
        }
    

    使用map将 [String] 转换为拆分 [[String]] ,然后使用reduce构建 [String:Int] 的字典 .

    或者,通过添加 Dictionary 的扩展名:

    extension Dictionary {
        init(elements:[(Key, Value)]) {
            self.init()
            for (key, value) in elements {
                updateValue(value, forKey: key)
            }
        }
    }
    

    (相当有用的扩展顺便说一句,你可以在字典上使用它进行很多map / filter操作,真的很遗憾它默认不存在)

    它变得更简单:

    let dict = Dictionary(elements: entries
        .map({ $0.componentsSeparatedByString("=") })
        .map({ ($0[0], Int($0[1])!)})
    )
    

    当然,您也可以组合两个 Map 调用,但我更喜欢拆分各个变换 .

    如果要添加一些错误检查,可以使用 flatMap 而不是 map

    let dict2 = [String:Int](elements: entries
        .map({ $0.componentsSeparatedByString("=") })
        .flatMap({
            if $0.count == 2, let value = Int($0[1]) {
                return ($0[0], value)
            } else {
                return nil
            }})
    )
    

    同样,如果你愿意,你可以显然将 map 合并到_178015中或者为了简单起见将它们分开 .

    let dict2 = [String:Int](elements: entries.flatMap {
        let parts = $0.componentsSeparatedByString("=")
        if parts.count == 2, let value = Int(parts[1]) {
            return (parts[0], value)
        } else {
            return nil
        }}
    )
    
  • 3

    我喜欢@paulgriffiths的答案,但是如果你对运行时错误有极大的厌恶,你可以更进一步,以确保初始数组中的每个字符串实际上都有两个必需的元素......

    与其他代码相比,此代码的重要区别在于我检查以确保字符串中实际上存在"=",并且两侧都有元素 . flatMap 有效地过滤掉任何失败的内容 .

    extension Dictionary {
        func withUpdate(key: Key, value: Value) -> Dictionary<Key, Value> {
            var result = self
            result[key] = value
            return result
        }
    }
    
    let entries = ["x=5", "y=7", "z=10"]
    
    let keyValues = entries.flatMap { str -> (String, String)? in
        let split = str.characters.split("=").map(String.init)
        return split.count > 1 ? (split[0], split[1]) : nil
    }
    
    let keyValuePairs = keyValues.reduce([String: String]()) { $0.withUpdate($1.0, value: $1.1) }
    
  • 0

    一种方法是使用 mapreduce 两个阶段,以元组作为中间值,例如:

    let entries = ["x=5", "y=7", "z=10"]
    
    let dict = entries.map { (str) -> (String, String) in
        let elements = str.characters.split("=").map(String.init)
        return (elements[0], elements[1])
        }.reduce([String:String]()) { (var dict, kvpair) in
            dict[kvpair.0] = kvpair.1
            return dict
    }
    
    for key in dict.keys {
        print("Value for key '\(key)' is \(dict[key]).")
    }
    

    输出:

    Value for key 'y' is Optional("7").
    Value for key 'x' is Optional("5").
    Value for key 'z' is Optional("10").
    

    或者使用具有相同输出的单个 reduce

    let entries = ["x=5", "y=7", "z=10"]
    
    let dict = entries.reduce([String:String]()) { (var dict, entry) in
        let elements = entry.characters.split("=").map(String.init)
        dict[elements[0]] = elements[1]
        return dict
    }
    
    for key in dict.keys {
        print("Value for key '\(key)' is \(dict[key]).")
    }
    
  • 0

    使用 Swift 4 的新 reduce(into: Result) 方法:

    let keyValuePairs = entries.reduce(into: [String:String]()) { (dict, entry) in
        let key = String(entry.first!)
        let value = String(entry.last!)
        dict[entry.first!] = entry.last!
    }
    

    当然,可以改进String的拆分 .

  • 0

    对于喜欢超载和单线的其他人 .

    public func +<K, V>(lhs: [K:V], rhs: [K:V]) -> [K:V] {
        var lhs: [K:V] = lhs
        for (key, value) in rhs {
            lhs[key] = value
        }
        return lhs
    }
    
    let array = ["x=5", "y=7", "z=10"]
    let dictionary = array.map({ $0.componentsSeparatedByString("=") }).reduce([:]) { $0 + [$1[0]: $1[1]] }
    
    print(dictionary) // ["y": "7", "x": "5", "z": "10"]
    
  • 8

    如果您有两个并行数组,则可以使用 zip()Array()David Berry's Dictionary extension

    let numbers = [10, 9, 8]
    let strings = ["one", "two", "three", "four"]
    
    let dictionary = Dictionary(elements: Array(zip(numbers, strings)))
    // == [10: "one", 9: "two", 8: "three"]
    

    别忘了添加扩展名:

    extension Dictionary {
        init(elements:[(Key, Value)]) {
            self.init()
            for (key, value) in elements {
                updateValue(value, forKey: key)
            }
        }
    }
    
  • 1

    简单方法:

    let array = ["key1", "key2", "key3"]
    let dict =  array.flatMap({["\($0)" : "value"]})
    

    输出:

    [(键:“key1”,值:“value”),(键:“key2”,值:“value”),(键:“key3”,值:“value”)]


    更复杂的方式:

    let array = ["key1", "key2", "key3"]
    let dict =  array.enumerated().flatMap({["\($0.element)" : "value\($0.offset)"]})
    

    输出:

    [(密钥:“key1”,值:“value0”),(密钥:“key2”,值:“value1”),(密钥:“key3”,值:“value2”)]

相关问题