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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 09:42:36  来源:igfitidea点击:

Map array of objects to Dictionary in Swift

iosarraysswiftdictionary

提问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 myArrayto 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 是否有任何优雅的方式来使用函数式方法mapflatMap...或其他现代 Swift 风格来做到这一点

回答by possen

Since Swift 4you can do @Tj3n's approach more cleanly and efficiently using the intoversion of reduceIt 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)]

Intoparameter 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 mapis not a good example of this, because its just same as looping, you can use reduceinstead, 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 Dictionarytype, for example from tuples:

您可以为Dictionary类型编写自定义初始化程序,例如从元组:

##代码##

and then use mapfor 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 peopleByPositioncould be a let.

如果有一种方法可以将最后两行组合起来,这样就peopleByPosition可以是一个let.

We could make an extension to Array that does that!

我们可以对 Array 进行扩展来做到这一点!

##代码##

Then we can just do

那么我们就可以做

##代码##

回答by prashant

##代码##