大きな配列があり、キー(ルックアップ)でアクセスする必要があるため、辞書を作成する必要があります。そうするためにSwift 3.0に組み込み関数がありますか、それとも自分で書く必要がありますか?
最初にキー「String」を持つクラスにそれが必要になり、後で多目的(すべてのタイプのデータとキー)のテンプレートバージョンを作成できるようになります。
2019年の注意。これは、現在、単純にSwiftに組み込まれている、uniqueKeysWithValues
および同様の呼び出しです。
次のようなものを探していると思います:
extension Array {
public func toDictionary<Key: Hashable>(with selectKey: (Element) -> Key) -> [Key:Element] {
var dict = [Key:Element]()
for element in self {
dict[selectKey(element)] = element
}
return dict
}
}
次のことができます。
struct Person {
var name: String
var surname: String
var identifier: String
}
let arr = [Person(name: "John", surname: "Doe", identifier: "JOD"),
Person(name: "Jane", surname: "Doe", identifier: "JAD")]
let dict = arr.toDictionary { $0.identifier }
print(dict) // Result: ["JAD": Person(name: "Jane", surname: "Doe", identifier: "JAD"), "JOD": Person(name: "John", surname: "Doe", identifier: "JOD")]
コードをより一般的にしたい場合は、Sequence
の代わりにArray
にこの拡張機能を追加することもできます。
extension Sequence {
public func toDictionary<Key: Hashable>(with selectKey: (Iterator.Element) -> Key) -> [Key:Iterator.Element] {
var dict: [Key:Iterator.Element] = [:]
for element in self {
dict[selectKey(element)] = element
}
return dict
}
}
これにより、シーケンスが繰り返され、場合によっては副作用が生じる可能性があることに注意してください。
それは(Swift 4)で?)
let dict = Dictionary(uniqueKeysWithValues: array.map{ ($0.key, $0) })
(注-キーの重複が懸念される場合は、バリエーションを使用できますDictionary#keysAndValues#uniquingKeysWith
これにより、あなたはpesを扱うことができます。)
On Swift 4、これを達成するには、Dictionary's_grouping:by:
_初期化子を使用します。
例:[〜#〜] a [〜#〜]という名前のクラスがあります
_class A {
var name: String
init(name: String) {
self.name = name
}
// .
// .
// .
// other declations and implementions
}
_
次に、タイプ[〜#〜] a [〜#〜]のオブジェクトの配列があります
_let a1 = A(name: "Joy")
let a2 = A(name: "Ben")
let a3 = A(name: "Boy")
let a4 = A(name: "Toy")
let a5 = A(name: "Tim")
let array = [a1, a2, a3, a4, a5]
_
すべての名前を最初の文字でグループ化して辞書を作成するとします。これを実現するには、Swifts Dictionary(grouping:by:)
を使用します
_let dictionary = Dictionary(grouping: array, by: { $0.name.first! })
// this will give you a dictionary
// ["J": [a1], "B": [a2, a3], "T": [a4, a5]]
_
ただし、結果の辞書「辞書」のタイプは
_[String : [A]]
_
itis notタイプ
_[String : A]
_
ご想像の通り。 (後者を実現するには_#uniqueKeysWithValues
_を使用します。)
他の人がすでに言ったように、私たちはどちらが鍵であるかを理解する必要があります。
しかし、私はあなたの質問の私の解釈に対する解決策を提供しようとしています。
struct User {
let id: String
let firstName: String
let lastName: String
}
ここでは、同じ
id
を持つ2人のユーザーが存在できないと想定しています。
let users: [User] = ...
let dict = users.reduce([String:User]()) { (result, user) -> [String:User] in
var result = result
result[user.id] = user
return result
}
dict
は辞書であり、key
はuser id
およびvalue
はuser value
。
id
を介してユーザーにアクセスするには、次のように書くことができます。
let user = dict["123"]
指定されたタイプElement
の配列、およびkey
のElement
を決定するクロージャーを指定すると、次の汎用関数はタイプのDictionary
を生成します[Key:Element]
func createIndex<Key, Element>(elms:[Element], extractKey:(Element) -> Key) -> [Key:Element] where Key : Hashable {
return elms.reduce([Key:Element]()) { (dict, Elm) -> [Key:Element] in
var dict = dict
dict[extractKey(Elm)] = Elm
return dict
}
}
例
let users: [User] = [
User(id: "a0", firstName: "a1", lastName: "a2"),
User(id: "b0", firstName: "b1", lastName: "b2"),
User(id: "c0", firstName: "c1", lastName: "c2")
]
let dict = createIndex(elms: users) { $0.id }
// ["b0": {id "b0", firstName "b1", lastName "b2"}, "c0": {id "c0", firstName "c1", lastName "c2"}, "a0": {id "a0", firstName "a1", lastName "a2"}]
Martin Rで述べたように、reduceは関連するクロージャーの反復ごとに新しい辞書を作成します。これにより、大量のメモリが消費される可能性があります。
createIndex
関数の別のバージョンは、スペース要件がO(n)で、nはelmsの長さです。
func createIndex<Key, Element>(elms:[Element], extractKey:(Element) -> Key) -> [Key:Element] where Key : Hashable {
var dict = [Key:Element]()
for Elm in elms {
dict[extractKey(Elm)] = Elm
}
return dict
}
この拡張機能はすべてのシーケンス(配列を含む)で機能し、キーと値の両方を選択できます。
extension Sequence {
public func toDictionary<K: Hashable, V>(_ selector: (Iterator.Element) throws -> (K, V)?) rethrows -> [K: V] {
var dict = [K: V]()
for element in self {
if let (key, value) = try selector(element) {
dict[key] = value
}
}
return dict
}
}
例:
let nameLookup = persons.toDictionary{($0.name, $0)}
以下は、配列を辞書に変換します。
let firstArray = [2,3,4,5,5]
let dict = Dictionary(firstArray.map { ($0, 1) } , uniquingKeysWith: +)
単純にやるだけで、
let items = URLComponents(string: "https://im.qq.com?q=13&id=23")!.queryItems!
var dic = [String: Any?]()
items.foreach {
dic[$0.name] = $0.value
}
reduce
はあまり適していませんが、
let dic: [String: Any?] = items.reduce([:]) { (result: [String: Any?], item: URLQueryItem) -> [String: Any?] in
var r = result
r[item.name] = item.value // will create an copy of result!!!!!!
return r
}
あなたの質問から理解しているように、Array
をDictionary
に変換したいと思います。
私の場合、extension
にArray
を作成し、辞書のキーはArray
のインデックスになります。
例:
var intArray = [2, 3, 5, 3, 2, 1]
extension Array where Element: Any {
var toDictionary: [Int:Element] {
var dictionary: [Int:Element] = [:]
for (index, element) in enumerate() {
dictionary[index] = element
}
return dictionary
}
}
let dic = intArray.toDictionary
Mapで設定されたパターンに従い、Swiftを削減する場合は、次のような素敵で機能的なことを行うことができます。
extension Array {
func keyBy<Key: Hashable>(_ keyFor: (Element) -> Key) -> [Key: Element] {
var ret = [Key: Element]()
for item in self{
ret[keyFor(item)] = item
}
return ret
}
}
使用法:
struct Dog {
let id: Int
}
let dogs = [Dog(id: 1), Dog(id: 2), Dog(id: 3), Dog(id: 4)]
let dogsById = dogs.keyBy({ $0.id })
// [4: Dog(id: 4), 1: Dog(id: 1), 3: Dog(id: 3), 2: Dog(id: 2)]