Ottieni un array di valori di proprietà da un array di oggetti


113

C'è una classe chiamata Employee.

class Employee {

    var id: Int
    var firstName: String
    var lastName: String
    var dateOfBirth: NSDate?

    init(id: Int, firstName: String, lastName: String) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
    }
}

E ho una serie di Employeeoggetti. Ciò di cui ho bisogno ora è estrarre la ids di tutti quegli oggetti in quell'array in un nuovo array.

Ho anche trovato questa domanda simile . Ma è in Objective-C quindi viene utilizzato valueForKeyPathper ottenere questo risultato.

Come posso farlo in Swift?

Risposte:


234

Puoi usare il mapmetodo, che trasforma un array di un certo tipo in un array di un altro tipo - nel tuo caso, da array di Employeea array di Int:

var array = [Employee]()
array.append(Employee(id: 4, firstName: "", lastName: ""))
array.append(Employee(id: 2, firstName: "", lastName: ""))

let ids = array.map { $0.id }

1
Questo è ciò che mapfa: trasforma un array di Employeein un array di Int, riempito con il idcampo. Che equivale a dire "estrai il campo id da tutte le istanze di Employeee inseriscili in un array"
Antonio

4
@ Isuru, questa risposta fa esattamente quello che vuoi. Crea un nuovo array chiamato idsdi tutti i idvalori dall'array di Employees. Nota, lascia intatto l'array originale.
vacawama

2
Sembra che nella versione beta di Swift 2 la sintassi corretta sarebbearray.map( { $0.id })
TotoroTotoro

10
se stai usando un optional, assicurati di farlo! esso. Mi ci sono volute ore.
Chris

2
@Chris lo scartamento forzato di solito è una cattiva pratica, perché se zero provocherà l'arresto anomalo dell'app. Usalo solo quando strettamente richiesto, e preferisci invece la rilegatura opzionale (o qualsiasi altro scartamento "morbido")
Antonio

81

Swift 5 offre molti modi per ottenere un array di valori di proprietà da un array di oggetti simili. In base alle tue esigenze, puoi scegliere uno dei sei seguenti esempi di codice di Playground per risolvere il tuo problema.


1. Usando il mapmetodo

Con Swift, i tipi conformi al Sequenceprotocollo hanno un map(_:)metodo. Il codice di esempio seguente mostra come utilizzarlo:

class Employee {
    
    let id: Int, firstName: String, lastName: String
    
    init(id: Int, firstName: String, lastName: String) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
    }

}

let employeeArray = [
    Employee(id: 1, firstName: "Jon", lastName: "Skeet"),
    Employee(id: 2, firstName: "Darin", lastName: "Dimitrov"),
    Employee(id: 4, firstName: "Hans", lastName: "Passant")
]

let idArray = employeeArray.map({ (employee: Employee) -> Int in
    employee.id
})
// let idArray = employeeArray.map { $0.id } // also works
print(idArray) // prints [1, 2, 4]

2. Utilizzo di forloop

class Employee {
    
    let id: Int, firstName: String, lastName: String

    init(id: Int, firstName: String, lastName: String) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
    }

}

let employeeArray = [
    Employee(id: 1, firstName: "Jon", lastName: "Skeet"),
    Employee(id: 2, firstName: "Darin", lastName: "Dimitrov"),
    Employee(id: 4, firstName: "Hans", lastName: "Passant")
]

var idArray = [Int]()    
for employee in employeeArray {
    idArray.append(employee.id)
}
print(idArray) // prints [1, 2, 4]

3. Utilizzo di whileloop

Nota che con Swift, dietro le quinte, un forloop è solo un whileloop su un sequenceiteratore di (vedi IteratorProtocol per maggiori dettagli).

class Employee {
    
    let id: Int, firstName: String, lastName: String
    
    init(id: Int, firstName: String, lastName: String) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
    }

}

let employeeArray = [
    Employee(id: 1, firstName: "Jon", lastName: "Skeet"),
    Employee(id: 2, firstName: "Darin", lastName: "Dimitrov"),
    Employee(id: 4, firstName: "Hans", lastName: "Passant")
]

var idArray = [Int]()
var iterator = employeeArray.makeIterator()    
while let employee = iterator.next() {
    idArray.append(employee.id)
}
print(idArray) // prints [1, 2, 4]

4. Utilizzo di un structche è conforme a IteratorProtocole Sequenceprotocolli

class Employee {
    
    let id: Int, firstName: String, lastName: String
    
    init(id: Int, firstName: String, lastName: String) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
    }
    
}

struct EmployeeSequence: Sequence, IteratorProtocol {
    
    let employeeArray: [Employee]
    private var index = 0
    
    init(employeeArray: [Employee]) {
        self.employeeArray = employeeArray
    }
    
    mutating func next() -> Int? {
        guard index < employeeArray.count else { return nil }
        defer { index += 1 }
        return employeeArray[index].id
    }
    
}

let employeeArray = [
    Employee(id: 1, firstName: "Jon", lastName: "Skeet"),
    Employee(id: 2, firstName: "Darin", lastName: "Dimitrov"),
    Employee(id: 4, firstName: "Hans", lastName: "Passant")
]
let employeeSequence = EmployeeSequence(employeeArray: employeeArray)
let idArray = Array(employeeSequence)
print(idArray) // prints [1, 2, 4]

5. Utilizzo Collectiondell'estensione del protocollo eAnyIterator

class Employee {
    
    let id: Int, firstName: String, lastName: String
    
    init(id: Int, firstName: String, lastName: String) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
    }

}

extension Collection where Iterator.Element: Employee {
    
    func getIDs() -> Array<Int> {
        var index = startIndex
        let iterator: AnyIterator<Int> = AnyIterator {
            defer { index = self.index(index, offsetBy: 1) }
            return index != self.endIndex ? self[index].id : nil
        }
        return Array(iterator)
    }
    
}

let employeeArray = [
    Employee(id: 1, firstName: "Jon", lastName: "Skeet"),
    Employee(id: 2, firstName: "Darin", lastName: "Dimitrov"),
    Employee(id: 4, firstName: "Hans", lastName: "Passant")
]

let idArray = employeeArray.getIDs()
print(idArray) // prints [1, 2, 4]

6. Utilizzo NSArraydel value(forKeyPath:)metodo di KVC e

Nota che questo esempio richiede class Employeedi ereditare da NSObject.

import Foundation

class Employee: NSObject {

    @objc let id: Int, firstName: String, lastName: String

    init(id: Int, firstName: String, lastName: String) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
    }

}

let employeeArray = [
    Employee(id: 1, firstName: "Jon", lastName: "Skeet"),
    Employee(id: 2, firstName: "Darin", lastName: "Dimitrov"),
    Employee(id: 4, firstName: "Hans", lastName: "Passant")
]

let employeeNSArray = employeeArray as NSArray
if let idArray = employeeNSArray.value(forKeyPath: #keyPath(Employee.id)) as? [Int] {
    print(idArray) // prints [1, 2, 4]
}

5
enorme ... Questo è per quanto ho capito elenco completo di possibili approcci
Iniezioni
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.