我想在字典中的所有键上映射一个函数。我希望以下类似的方法可以工作,但是过滤器无法直接应用于字典。实现这一目标的最干净的方法是什么?
在此示例中,我尝试将每个值加1。但这对于示例来说是偶然的-主要目的是弄清楚如何将map()应用于字典。
var d = ["foo" : 1, "bar" : 2]
d.map() {
$0.1 += 1
}
map
做的。您需要的是一种将迭代隐藏在扩展/闭包后面的方式,因此您不必每次使用它时都去查看它。
我想在字典中的所有键上映射一个函数。我希望以下类似的方法可以工作,但是过滤器无法直接应用于字典。实现这一目标的最干净的方法是什么?
在此示例中,我尝试将每个值加1。但这对于示例来说是偶然的-主要目的是弄清楚如何将map()应用于字典。
var d = ["foo" : 1, "bar" : 2]
d.map() {
$0.1 += 1
}
map
做的。您需要的是一种将迭代隐藏在扩展/闭包后面的方式,因此您不必每次使用它时都去查看它。
Answers:
迅捷4+
好消息!Swift 4包含一种mapValues(_:)
方法,该方法使用相同的键但值不同来构造字典的副本。它还包含一个filter(_:)
重载函数Dictionary
,该重载函数返回a 和,init(uniqueKeysWithValues:)
并使用init(_:uniquingKeysWith:)
初始化程序Dictionary
从任意元组序列创建a 。这意味着,如果您想同时更改键和值,则可以这样说:
let newDict = Dictionary(uniqueKeysWithValues:
oldDict.map { key, value in (key.uppercased(), value.lowercased()) })
还有一些新的API可将字典合并在一起,用默认值替换缺少的元素,对值进行分组(将集合转换为数组的字典,由将集合映射到某个函数上的结果作为关键)。
在讨论介绍这些功能的建议SE-0165期间,我多次提出了这个Stack Overflow的答案,并且我认为大量的赞成票有助于证明需求。因此,感谢您的帮助,使Swift变得更好!
map
,可能产生冲突密钥的A 仍然有用map
。(另一方面,您可能会争辩说,仅映射值是map
对字典的自然解释-原始发布者的示例和我的都仅修改值,并且从概念上讲,map
在数组上仅修改值,而不是索引。)
try
:return Dictionary<Key, OutValue>(try map { (k, v) in (k, try transform(v)) })
DictionaryExtension.swift:13:16: Argument labels '(_:)' do not match any available overloads
Argument labels '(_:)' do not match any available overloads
实现最后一个扩展。不太确定如何解决它:/
Dictionary
前面示例之一中添加的初始化程序。确保同时包含它们。
使用Swift 5,您可以使用以下五个摘要之一来解决您的问题。
Dictionary
mapValues(_:)
方法let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.mapValues { value in
return value + 1
}
//let newDictionary = dictionary.mapValues { $0 + 1 } // also works
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
Dictionary
map
方法和init(uniqueKeysWithValues:)
初始化let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let tupleArray = dictionary.map { (key: String, value: Int) in
return (key, value + 1)
}
//let tupleArray = dictionary.map { ($0, $1 + 1) } // also works
let newDictionary = Dictionary(uniqueKeysWithValues: tupleArray)
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
Dictionary
reduce(_:_:)
方法或reduce(into:_:)
方法let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.reduce([:]) { (partialResult: [String: Int], tuple: (key: String, value: Int)) in
var result = partialResult
result[tuple.key] = tuple.value + 1
return result
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.reduce(into: [:]) { (result: inout [String: Int], tuple: (key: String, value: Int)) in
result[tuple.key] = tuple.value + 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
Dictionary
subscript(_:default:)
下标let dictionary = ["foo": 1, "bar": 2, "baz": 5]
var newDictionary = [String: Int]()
for (key, value) in dictionary {
newDictionary[key, default: value] += 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
Dictionary
subscript(_:)
下标let dictionary = ["foo": 1, "bar": 2, "baz": 5]
var newDictionary = [String: Int]()
for (key, value) in dictionary {
newDictionary[key] = value + 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
虽然这里的大多数答案都集中在如何映射整个字典(键和值)上,但这个问题实际上只想映射值。这是一个重要的区别,因为映射值允许您保证相同数量的条目,而键和值的映射可能会导致键重复。
这是扩展名,mapValues
它允许您仅映射值。请注意,它还使用init
来自键/值对序列的来扩展字典,这比从数组初始化它要通用一些:
extension Dictionary {
init<S: SequenceType where S.Generator.Element == Element>
(_ seq: S) {
self.init()
for (k,v) in seq {
self[k] = v
}
}
func mapValues<T>(transform: Value->T) -> Dictionary<Key,T> {
return Dictionary<Key,T>(zip(self.keys, self.values.map(transform)))
}
}
func mapValues<T>(_ transform: (_ value: Value) -> T) -> [Key: T] { var result = [Key: T]() for (key, val) in self { result[key] = transform(val) } return result }
。我发现它的阅读效果也更好。是否存在性能问题?
最干净的方法是只添加map
到Dictionary中:
extension Dictionary {
mutating func map(transform: (key:KeyType, value:ValueType) -> (newValue:ValueType)) {
for key in self.keys {
var newValue = transform(key: key, value: self[key]!)
self.updateValue(newValue, forKey: key)
}
}
}
检查它是否有效:
var dic = ["a": 50, "b": 60, "c": 70]
dic.map { $0.1 + 1 }
println(dic)
dic.map { (key, value) in
if key == "a" {
return value
} else {
return value * 2
}
}
println(dic)
输出:
[c: 71, a: 51, b: 61]
[c: 142, a: 51, b: 122]
SequenceType.map
不是变异函数。您的示例可以重写为遵循的现有合同map
,但是与接受的答案相同。
您也可以使用reduce
代替地图。reduce
有能力做任何事情map
都能做的更多!
let oldDict = ["old1": 1, "old2":2]
let newDict = reduce(oldDict, [String:Int]()) { dict, pair in
var d = dict
d["new\(pair.1)"] = pair.1
return d
}
println(newDict) // ["new1": 1, "new2": 2]
将其包装在扩展中非常容易,但是即使没有扩展,它也允许您通过一个函数调用来完成所需的操作。
let newDict = oldDict.reduce([String:Int]()) { (var dict, pair) in dict["new\(pair.1)"] = pair.1; return dict }
事实证明您可以做到这一点。您要做的是MapCollectionView<Dictionary<KeyType, ValueType>, KeyType>
根据字典keys
方法返回的内容创建一个数组。(这里的信息)然后可以映射此数组,并将更新后的值传递回字典。
var dictionary = ["foo" : 1, "bar" : 2]
Array(dictionary.keys).map() {
dictionary.updateValue(dictionary[$0]! + 1, forKey: $0)
}
dictionary
我正在寻找一种将字典直接映射到具有自定义对象的类型化Array的方法。在此扩展中找到了解决方案:
extension Dictionary {
func mapKeys<U> (transform: Key -> U) -> Array<U> {
var results: Array<U> = []
for k in self.keys {
results.append(transform(k))
}
return results
}
func mapValues<U> (transform: Value -> U) -> Array<U> {
var results: Array<U> = []
for v in self.values {
results.append(transform(v))
}
return results
}
func map<U> (transform: Value -> U) -> Array<U> {
return self.mapValues(transform)
}
func map<U> (transform: (Key, Value) -> U) -> Array<U> {
var results: Array<U> = []
for k in self.keys {
results.append(transform(k as Key, self[ k ]! as Value))
}
return results
}
func map<K: Hashable, V> (transform: (Key, Value) -> (K, V)) -> Dictionary<K, V> {
var results: Dictionary<K, V> = [:]
for k in self.keys {
if let value = self[ k ] {
let (u, w) = transform(k, value)
results.updateValue(w, forKey: u)
}
}
return results
}
}
如下使用它:
self.values = values.map({ (key:String, value:NSNumber) -> VDLFilterValue in
return VDLFilterValue(name: key, amount: value)
})
迅捷3
我在Swift 3中尝试了一种简单的方法。
我想将[String:String?]映射到[String:String],我使用forEach而不是map或flat map。
let oldDict = ["key0": "val0", "key1": nil, "key1": "val2","key2": nil]
var newDict = [String: String]()
oldDict.forEach { (source: (key: String, value: String?)) in
if let value = source.value{
newDict[source.key] = value
}
}
斯威夫特5
字典的map函数带有此语法。
dictData.map(transform: ((key: String, value: String)) throws -> T)
您可以为此设置闭包值
var dictData: [String: String] = [
"key_1": "test 1",
"key_2": "test 2",
"key_3": "test 3",
"key_4": "test 4",
"key_5": "test 5",
]
dictData.map { (key, value) in
print("Key :: \(key), Value :: \(value)")
}
输出将是:
Key :: key_5, Value :: test 5
Key :: key_1, Value :: test 1
Key :: key_3, Value :: test 3
Key :: key_2, Value :: test 2
Key :: key_4, Value :: test 4
可能会发出此警告 Result of call to 'map' is unused
然后_ =
在变量之前设置。
可能会帮助您,谢谢。
我认为问题在于保留原始字典的键并以某种方式映射其所有值。
让我们概括地说,我们可能想将所有值映射到另一种类型。
所以我们想开始的是一个字典和一个闭包(一个函数),最后是一个新的字典。问题是,当然,Swift的严格类型会妨碍您的操作。闭包需要指定要输入的类型和输出的类型,因此,我们不能创建采用通用闭包的方法,除非是在泛型的上下文中。因此,我们需要一个泛型函数。
其他解决方案集中于在Dictionary泛型结构本身的泛型世界中执行此操作,但是我发现就顶级函数而言更容易思考。例如,我们可以这样写,其中K是键类型,V1是起始字典的值类型,而V2是结束字典的值类型:
func mapValues<K,V1,V2>(d1:[K:V1], closure:(V1)->V2) -> [K:V2] {
var d2 = [K:V2]()
for (key,value) in zip(d1.keys, d1.values.map(closure)) {
d2.updateValue(value, forKey: key)
}
return d2
}
这是一个调用它的简单示例,只是为了证明泛型确实在编译时可以解决自身问题:
let d : [String:Int] = ["one":1, "two":2]
let result = mapValues(d) { (i : Int) -> String in String(i) }
我们从的字典开始,然后以的字典[String:Int]
结束,方法是[String:String]
通过闭包转换第一个字典的值。
(编辑:我现在看到的是,这实际上与AirspeedVelocity的解决方案相同,只是我没有添加让字典从zip序列中提取出来的Dictionary初始化器的额外优雅。)
迅捷3
用法:
let bob = ["a": "AAA", "b": "BBB", "c": "CCC"]
bob.mapDictionary { ($1, $0) } // ["BBB": "b", "CCC": "c", "AAA": "a"]
延期:
extension Dictionary {
func mapDictionary(transform: (Key, Value) -> (Key, Value)?) -> Dictionary<Key, Value> {
var dict = [Key: Value]()
for key in keys {
guard let value = self[key], let keyValue = transform(key, value) else {
continue
}
dict[keyValue.0] = keyValue.1
}
return dict
}
}
我只是想映射值(可能会更改它们的类型),包括此扩展名:
extension Dictionary {
func valuesMapped<T>(_ transform: (Value) -> T) -> [Key: T] {
var newDict = [Key: T]()
for (key, value) in self {
newDict[key] = transform(value)
}
return newDict
}
}
如果您有这本字典:
let intsDict = ["One": 1, "Two": 2, "Three": 3]
单行值转换如下所示:
let stringsDict = intsDict.valuesMapped { String($0 * 2) }
// => ["One": "2", "Three": "6", "Two": "4"]
多行值转换如下所示:
let complexStringsDict = intsDict.valuesMapped { (value: Int) -> String in
let calculationResult = (value * 3 + 7) % 5
return String("Complex number #\(calculationResult)")
}
// => ["One": "Complex number #0", "Three": ...
另一种方法是map
创建字典和reduce
,其中函数keyTransform
和valueTransform
是函数。
let dictionary = ["a": 1, "b": 2, "c": 3]
func keyTransform(key: String) -> Int {
return Int(key.unicodeScalars.first!.value)
}
func valueTransform(value: Int) -> String {
return String(value)
}
dictionary.map { (key, value) in
[keyTransform(key): valueTransform(value)]
}.reduce([Int:String]()) { memo, element in
var m = memo
for (k, v) in element {
m.updateValue(v, forKey: k)
}
return m
}
Swift 3我用这个
func mapDict(dict:[String:Any])->[String:String]{
var updatedDict:[String:String] = [:]
for key in dict.keys{
if let value = dict[key]{
updatedDict[key] = String(describing: value)
}
}
return updatedDict
}
用法:
let dict:[String:Any] = ["MyKey":1]
let mappedDict:[String:String] = mapDict(dict: dict)