我想从这个字符串数组中获取
let entries = ["x=5", "y=7", "z=10"]
到这个
let keyValuePairs = ["x" : "5", "y" : "7", "z" : "10"]
我尝试使用map
,但问题似乎是字典中的键值对不是一个独特的类型,它只是在我的脑海中,而不是在字典类型中所以我不能真的提供了一个转换函数,因为没有什么可以转换的。加map
返回一个数组,这样就不行了。
有什么想法吗?
答案 0 :(得分: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]
}
}
较旧的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
}
使用地图将[String]
转换为拆分[[String]]
,然后使用reduce构建[String:Int]
字典。
或者,通过向Dictionary
添加扩展程序:
extension Dictionary {
init(elements:[(Key, Value)]) {
self.init()
for (key, value) in elements {
updateValue(value, forKey: key)
}
}
}
(相当有用的扩展顺便说一句,你可以用它来进行字典上的很多地图/过滤操作,真的很遗憾它默认不存在)
变得更加简单:
let dict = Dictionary(elements: entries
.map({ $0.componentsSeparatedByString("=") })
.map({ ($0[0], Int($0[1])!)})
)
当然,您也可以将两个地图调用结合起来,但我更愿意分解各个变换。
如果您想添加一些错误检查,可以使用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
合并到flatMap
中,或者为了简单起见将其拆分。
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
}}
)
答案 1 :(得分:9)
一种方法是分为两个阶段,其中map
和reduce
以元组作为中间值,例如:
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]).")
}
答案 2 :(得分:8)
使用 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!
}
当然,可以改进字符串的拆分。
答案 3 :(得分:3)
已经有了很好的答案。以下是集合类型扩展的另一种方法。您可以将任何集合类型转换为字典,数组或集合。
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)")
答案 4 :(得分:1)
我喜欢@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) }
答案 5 :(得分:0)
对于喜欢超载和单行的其他人。
jQuery(document).ready(function($) {
$('.exampleimg').click(function() {
$('.exampleimg').removeClass('exampleimgopen').addClass('exampleimgclose');
$(this).addClass('exampleimgopen').removeClass('exampleimgclose')
});
});
答案 6 :(得分:0)
如果您有两个并行数组,则可以使用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)
}
}
}
答案 7 :(得分:0)
简单方法:
let array = ["key1", "key2", "key3"]
let dict = array.flatMap({["\($0)" : "value"]})
输出:
[(键:&#34;键1和#34;,值:&#34;值&#34;),(键:&#34;键2&#34;,值:&#34;值&#34; ),(关键: &#34; key3&#34;,值:&#34;值&#34;)]
更复杂的方式:
let array = ["key1", "key2", "key3"]
let dict = array.enumerated().flatMap({["\($0.element)" : "value\($0.offset)"]})
输出:
[(键:&#34; key1&#34;,值:&#34; value0&#34;),(键:&#34;键2&#34;,值:&#34; value1&#34; ),(关键: &#34; key3&#34;,值:&#34; value2&#34;)]