Swift의 사전에 객체 배열 매핑
나는 여러 가지를 가지고 있습니다.Person의 개체:
class Person {
let name:String
let position:Int
}
배열은 다음과 같습니다.
let myArray = [p1,p1,p3]
지도를 만들고 싶습니다.myArray의 사전이 되다[position:name]일반적인 솔루션은 다음과 같습니다.
var myDictionary = [Int:String]()
for person in myArray {
myDictionary[person.position] = person.name
}
기능적 접근법으로 그것을 할 수 있는 스위프트의 우아한 방법이 있습니까?map,flatMap아니면 다른 현대적인 스위프트 스타일.
부터Swift 4당신은 @Tj3n의 접근법을 더 깨끗하고 효율적으로 사용할 수 있습니다.into의 버전reduce그것은 임시 사전과 반환 값을 없애서 더 빠르고 쉽게 읽을 수 있습니다.
샘플 코드 설정:
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매개 변수가 결과 유형의 빈 사전을 전달합니다.
let myDict = myArray.reduce(into: [Int: String]()) {
$0[$1.position] = $1.name
}
전달된 형식의 사전을 직접 반환합니다.into:
print(myDict) // [2: "c", 0: "h", 4: "b"]
알았어요.map이것의 좋은 예는 아닙니다, 왜냐하면 그것은 루프와 같기 때문에, 당신은 사용할 수 있습니다.reduce대신 각 개체를 결합하여 단일 값으로 변환하는 데 필요했습니다.
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"]
Swift 4 이상에서는 더 명확한 구문을 위해 아래 답변을 사용하십시오.
스위프트 4 이후로 당신은 이것을 매우 쉽게 할 수 있습니다.일련의 튜플(키와 값의 쌍)에서 사전을 작성하는 두 개의 새로운 이니셜라이저가 있습니다.키가 고유한 경우 다음을 수행할 수 있습니다.
let persons = [Person(name: "Franz", position: 1),
Person(name: "Heinz", position: 2),
Person(name: "Hans", position: 3)]
Dictionary(uniqueKeysWithValues: persons.map { ($0.position, $0.name) })
=>[1: "Franz", 2: "Heinz", 3: "Hans"]
키가 중복되면 런타임 오류와 함께 실패합니다.이 경우 다음 버전을 사용할 수 있습니다.
let persons = [Person(name: "Franz", position: 1),
Person(name: "Heinz", position: 2),
Person(name: "Hans", position: 1)]
Dictionary(persons.map { ($0.position, $0.name) }) { _, last in last }
=>[1: "Hans", 2: "Heinz"]
이것은 for 루프처럼 작동합니다.값을 "덮어쓰기"하지 않고 첫 번째 매핑을 고수하려면 다음을 사용할 수 있습니다.
Dictionary(persons.map { ($0.position, $0.name) }) { first, _ in first }
=>[1: "Franz", 2: "Heinz"]
Swift 4.2에는 시퀀스 요소를 사전으로 그룹화하는 세 번째 이니셜라이저가 추가되었습니다.사전 키는 폐쇄를 통해 파생됩니다.키가 동일한 요소는 순서와 동일한 순서로 배열됩니다.이렇게 하면 위와 유사한 결과를 얻을 수 있습니다.예:
Dictionary(grouping: persons, by: { $0.position }).mapValues { $0.last! }
=>[1: Person(name: "Hans", position: 1), 2: Person(name: "Heinz", position: 2)]
Dictionary(grouping: persons, by: { $0.position }).mapValues { $0.first! }
=>[1: Person(name: "Franz", position: 1), 2: Person(name: "Heinz", position: 2)]
KeyPath 기반 솔루션은 어떻습니까?
extension Array {
func dictionary<Key, Value>(withKey key: KeyPath<Element, Key>, value: KeyPath<Element, Value>) -> [Key: Value] {
reduce(into: [:]) { dictionary, element in
let key = element[keyPath: key]
let value = element[keyPath: value]
dictionary[key] = value
}
}
}
사용 방법은 다음과 같습니다.
struct HTTPHeader {
let field: String, value: String
}
let headers = [
HTTPHeader(field: "Accept", value: "application/json"),
HTTPHeader(field: "User-Agent", value: "Safari")
]
headers.dictionary(withKey: \.field, value: \.value) // ["Accept": "application/json", "User-Agent": "Safari"]
다음에 대한 사용자 정의 이니셜라이저를 작성할 수 있습니다.Dictionarytype(예: 튜플에서):
extension Dictionary {
public init(keyValuePairs: [(Key, Value)]) {
self.init()
for pair in keyValuePairs {
self[pair.0] = pair.1
}
}
}
그런 다음 사용합니다.map의 배열을 위하여Person:
var myDictionary = Dictionary(keyValuePairs: myArray.map{($0.position, $0.name)})
이것이 제가 사용해온 것입니다.
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[$0.position] = $0}
마지막 두 줄을 결합하여 다음과 같이 할 수 있는 방법이 있으면 좋겠습니다.peopleByPosition가능성이 있습니다let.
어레이를 확장할 수 있습니다!
extension Array {
func mapToDict<T>(by block: (Element) -> T ) -> [T: Element] where T: Hashable {
var map = [T: Element]()
self.forEach{ map[block($0)] = $0 }
return map
}
}
그러면 그냥 하면 됩니다.
let peopleByPosition = persons.mapToDict(by: {$0.position})
축소 함수를 사용할 수 있습니다.먼저 사용자 클래스에 지정된 이니셜라이저를 만들었습니다.
class Person {
var name:String
var position:Int
init(_ n: String,_ p: Int) {
name = n
position = p
}
}
나중에 값 배열을 초기화했습니다.
let myArray = [Person("Bill",1),
Person("Steve", 2),
Person("Woz", 3)]
마지막으로 사전 변수의 결과는 다음과 같습니다.
let dictionary = myArray.reduce([Int: Person]()){
(total, person) in
var totalMutable = total
totalMutable.updateValue(person, forKey: total.count)
return totalMutable
}
이런 거?
myArray.forEach({ myDictionary[$0.position] = $0.name })
extension Array {
func mapToDict<T>(by block: (Element) -> T ) -> [T: Element] where T: Hashable {
var map = [T: Element]()
self.forEach{ map[block($0)] = $0 }
return map
}
}
extension Array {
func toDictionary() -> [Int: Element] {
self.enumerated().reduce(into: [Int: Element]()) { $0[$1.offset] = $1.element }
}
}
언급URL : https://stackoverflow.com/questions/38454952/map-array-of-objects-to-dictionary-in-swift
'codememo' 카테고리의 다른 글
| aspx 페이지의 if 문 (0) | 2023.04.28 |
|---|---|
| ASP를 위한 Come 구현.NET? (0) | 2023.04.28 |
| Angular CLI를 제거/업그레이드하는 방법은 무엇입니까? (0) | 2023.04.28 |
| Bash를 사용하여 파일 크기를 확인하려면 어떻게 해야 합니까? (0) | 2023.04.28 |
| 항목 컨테이너 생성기입니다.ContainerFromItem()이 null을 반환합니까? (0) | 2023.04.28 |