ios 将对象数组映射到 Swift 中的字典
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38454952/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Map array of objects to Dictionary in Swift
提问by iOSGeek
I have an array of Person
's objects:
我有一组Person
's 对象:
class Person {
let name:String
let position:Int
}
and the array is:
数组是:
let myArray = [p1,p1,p3]
I want to map myArray
to be a Dictionary of [position:name]
the classic solution is:
我想映射myArray
为字典[position:name]
的经典解决方案是:
var myDictionary = [Int:String]()
for person in myArray {
myDictionary[person.position] = person.name
}
is there any elegant way by Swift to do that with the functional approach map
, flatMap
... or other modern Swift style
Swift 是否有任何优雅的方式来使用函数式方法map
、flatMap
...或其他现代 Swift 风格来做到这一点
回答by possen
Since Swift 4
you can do @Tj3n's approach more cleanly and efficiently using the into
version of reduce
It gets rid of the temporary dictionary and the return value so it is faster and easier to read.
由于Swift 4
您可以使用Itinto
版本更干净、更有效地执行 @Tj3n 的方法,reduce
因此摆脱了临时字典和返回值,因此它更快更容易阅读。
Sample code setup:
示例代码设置:
struct Person {
let name: String
let position: Int
}
let myArray = [Person(name:"h", position: 0), Person(name:"b", position:4), Person(name:"c", position:2)]
Into
parameter is passed empty dictionary of result type:
Into
参数被传递结果类型的空字典:
let myDict = myArray.reduce(into: [Int: String]()) {
print(myDict) // [2: "c", 0: "h", 4: "b"]
[.position] = .name
}
Directly returns a dictionary of the type passed in into
:
直接返回传入类型的字典into
:
let myDictionary = myArray.reduce([Int: String]()) { (dict, person) -> [Int: String] in
var dict = dict
dict[person.position] = person.name
return dict
}
//[2: "b", 3: "c", 1: "a"]
回答by Tj3n
Okay map
is not a good example of this, because its just same as looping, you can use reduce
instead, it took each of your object to combine and turn into single value:
好的map
不是一个很好的例子,因为它与循环相同,你可以使用reduce
它来代替,它需要你的每个对象组合并变成单个值:
let persons = [Person(name: "Franz", position: 1),
Person(name: "Heinz", position: 2),
Person(name: "Hans", position: 3)]
Dictionary(uniqueKeysWithValues: persons.map { (let persons = [Person(name: "Franz", position: 1),
Person(name: "Heinz", position: 2),
Person(name: "Hans", position: 1)]
Dictionary(persons.map { (Dictionary(persons.map { (Dictionary(grouping: persons, by: { Dictionary(grouping: persons, by: { extension Dictionary {
public init(keyValuePairs: [(Key, Value)]) {
self.init()
for pair in keyValuePairs {
self[pair.0] = pair.1
}
}
}
.position }).mapValues { var myDictionary = Dictionary(keyValuePairs: myArray.map{(extension Array {
func dictionary<Key, Value>(withKey key: KeyPath<Element, Key>, value: KeyPath<Element, Value>) -> [Key: Value] {
return reduce(into: [:]) { dictionary, element in
let key = element[keyPath: key]
let value = element[keyPath: value]
dictionary[key] = value
}
}
}
.position, struct HTTPHeader {
let field: String, value: String
}
let headers = [
HTTPHeader(field: "Accept", value: "application/json"),
HTTPHeader(field: "User-Agent", value: "Safari"),
]
let allHTTPHeaderFields = headers.dictionary(withKey: \.field, value: \.value)
// allHTTPHeaderFields == ["Accept": "application/json", "User-Agent": "Safari"]
.name)})
.first! }
.position }).mapValues { myArray.forEach({ myDictionary[class Person {
var name:String
var position:Int
init(_ n: String,_ p: Int) {
name = n
position = p
}
}
.position] = let myArray = [Person("Bill",1),
Person("Steve", 2),
Person("Woz", 3)]
.name })
.last! }
.position, let dictionary = myArray.reduce([Int: Person]()){
(total, person) in
var totalMutable = total
totalMutable.updateValue(person, forKey: total.count)
return totalMutable
}
.name) }) { first, _ in first }
.position, struct Person {
let name:String
let position:Int
}
let persons = [Person(name: "Franz", position: 1),
Person(name: "Heinz", position: 2),
Person(name: "Hans", position: 3)]
var peopleByPosition = [Int: Person]()
persons.forEach{peopleByPosition[extension Array {
func mapToDict<T>(by block: (Element) -> T ) -> [T: Element] where T: Hashable {
var map = [T: Element]()
self.forEach{ map[block(let peopleByPosition = persons.mapToDict(by: {extension Array {
func mapToDict<T>(by block: (Element) -> T ) -> [T: Element] where T: Hashable {
var map = [T: Element]()
self.forEach{ map[block(##代码##)] = ##代码## }
return map
}
}
.position})
)] = ##代码## }
return map
}
}
.position] = ##代码##}
.name) }) { _, last in last }
.position, ##代码##.name) })
In Swift 4 or higher please use the below answer for clearer syntax.
在 Swift 4 或更高版本中,请使用以下答案以获得更清晰的语法。
回答by Mackie Messer
Since Swift 4you can do this very easily. There are twonewinitializers that build a dictionary from a sequence of tuples (pairs of key and value). If the keys are guaranteed to be unique, you can do the following:
从Swift 4 开始,你可以很容易地做到这一点。有两个新的初始值设定项从元组序列(键值对)构建字典。如果保证键是唯一的,您可以执行以下操作:
##代码##=> [1: "Franz", 2: "Heinz", 3: "Hans"]
=> [1: "Franz", 2: "Heinz", 3: "Hans"]
This will fail with a runtime error if any key is duplicated. In that case you can use this version:
如果任何键重复,这将失败并出现运行时错误。在这种情况下,您可以使用此版本:
##代码##=> [1: "Hans", 2: "Heinz"]
=> [1: "Hans", 2: "Heinz"]
This behaves as your for loop. If you don't want to "overwrite" values and stick to the first mapping, you can use this:
这表现为您的 for 循环。如果您不想“覆盖”值并坚持使用第一个映射,则可以使用以下命令:
##代码##=> [1: "Franz", 2: "Heinz"]
=> [1: "Franz", 2: "Heinz"]
Swift 4.2adds a thirdinitializer that groups sequence elements into a dictionary. Dictionary keys are derived by a closure. Elements with the same key are put into an array in the same order as in the sequence. This allows you to achieve similar results as above. For example:
Swift 4.2添加了第三个初始化器,用于将序列元素分组到字典中。字典键由闭包派生。具有相同键的元素按照与序列中相同的顺序放入数组中。这使您可以获得与上述类似的结果。例如:
##代码##=> [1: Person(name: "Hans", position: 1), 2: Person(name: "Heinz", position: 2)]
=> [1: Person(name: "Hans", position: 1), 2: Person(name: "Heinz", position: 2)]
=> [1: Person(name: "Franz", position: 1), 2: Person(name: "Heinz", position: 2)]
=> [1: Person(name: "Franz", position: 1), 2: Person(name: "Heinz", position: 2)]
回答by Shadow Of
You may write custom initializer for Dictionary
type, for example from tuples:
您可以为Dictionary
类型编写自定义初始化程序,例如从元组:
and then use map
for your array of Person
:
然后map
用于您的数组Person
:
回答by lucamegh
How about a KeyPath based solution?
基于 KeyPath 的解决方案怎么样?
##代码##This is how you will used it:
这是你将如何使用它:
##代码##回答by Varun Goyal
Maybe something like this?
也许是这样的?
##代码##回答by David
You can use a reduce function. First I've created a designated initializer for Person class
您可以使用减少功能。首先,我为 Person 类创建了一个指定的初始化程序
##代码##Later, I've initialized an Array of values
后来,我初始化了一个值数组
##代码##And finally, the dictionary variable has the result:
最后,字典变量的结果是:
##代码##回答by datinc
This is what I have been using
这是我一直在使用的
##代码##Would be nice if there was a way to combine the last 2 lines so that peopleByPosition
could be a let
.
如果有一种方法可以将最后两行组合起来,这样就peopleByPosition
可以是一个let
.
We could make an extension to Array that does that!
我们可以对 Array 进行扩展来做到这一点!
##代码##Then we can just do
那么我们就可以做
##代码##