arrays - tutorial - read fasta python
Swift 3: Array to Dictionary? (8)
Tengo una gran variedad y necesito acceder a ella mediante una clave (una búsqueda), así que necesito crear el Diccionario. ¿Hay una función incorporada en Swift 3.0 para hacerlo, o tengo que escribirla yo mismo?
Primero lo necesitaré para una clase con la tecla "Cadena" y luego tal vez pueda escribir una versión de plantilla para fines generales (todo tipo de datos y clave).
¿Es eso (en Swift 4)?
let dict = Dictionary(uniqueKeysWithValues: array.map{ ($0.key, $0) })
Como entiendo de su pregunta, le gustaría convertir a Array
to Dictionary
.
En mi caso, creo una extension
para el Array
y las claves para el diccionario serán los índices del Array
.
Ejemplo:
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
Como ya han dicho otros, tenemos que entender cuáles son las claves.
Sin embargo, estoy tratando de proporcionar una solución a mi interpretación de su pregunta.
struct User {
let id: String
let firstName: String
let lastName: String
}
Aquí asumo que no pueden existir 2 usuarios con el mismo
id
let users: [User] = ...
let dict = users.reduce([String:User]()) { (result, user) -> [String:User] in
var result = result
result[user.id] = user
return result
}
Ahora dict
es un diccionario donde la key
es la user id
del user id
y el value
es el user value
.
Para acceder a un usuario a través de su id
, ahora puede simplemente escribir
let user = dict["123"]
Actualización # 1: enfoque general
Dada una matriz de un Element
tipo dado y un cierre que determina la key
de un Element
, la siguiente función genérica generará un Dictionary
de tipo [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
}
}
Ejemplo
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"}]
Actualización # 2
Como señaló Martin R, la reducción creará un nuevo diccionario para cada iteración del cierre relacionado. Esto podría llevar a un gran consumo de memoria.
Aquí hay otra versión de la función createIndex
donde el requisito de espacio es O (n) donde n es la longitud de los olmos.
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
}
Creo que estás buscando algo como esto:
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
}
}
Ahora puedes hacer:
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")]
Si desea que su código sea más general, incluso podría agregar esta extensión en Sequence
lugar de 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
}
}
Tenga en cuenta que esto hace que la secuencia se repita y en algunos casos podría tener efectos secundarios.
En Swift 4, puede lograr esto utilizando la grouping:by:
del Diccionario grouping:by:
inicializador
Por ejemplo: tienes clase llamada A
class A {
var name: String
init(name: String) {
self.name = name
}
// .
// .
// .
// other declations and implementions
}
A continuación, tienes una matriz de objetos de tipo 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]
Supongamos que desea crear un Diccionario agrupando todos los nombres por su primera letra. Utiliza Swifts Dictionary(grouping:by:)
para lograr esto
let dictionary = Dictionary(grouping: array, by: { $0.name.first! })
// this will give you a dictionary
// ["J": [a1], "B": [a2, a3], "T": [a4, a5]]
Esta extensión funciona para todas las secuencias (incluidas las matrices) y le permite seleccionar tanto la clave como el valor :
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
}
}
Ejemplo:
let nameLookup = persons.toDictionary{($0.name, $0)}
Lo siguiente convierte una matriz en un diccionario.
let firstArray = [2,3,4,5,5]
let dict = Dictionary(firstArray.map { ($0, 1) } , uniquingKeysWith: +)
Sólo hazlo simplemente,
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
no es muy adecuado,
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
}