Ruft ein Array von Eigenschaftswerten aus einem Objektarray ab

113

Es gibt eine Klasse namens 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
    }
}

Und ich habe eine Reihe von Employee Objekten. Was ich jetzt brauche, ist das ids aller dieser Objekte in diesem Array in ein neues Array zu extrahieren .

Ich fand das auch ähnlich Frage gefunden . Aber es ist in Objective-C, also wird es verwendet valueForKeyPath, um dies zu erreichen.

Wie kann ich das in Swift machen?

Isuru
quelle

Antworten:

234

Sie können die mapMethode verwenden, mit der ein Array eines bestimmten Typs in ein Array eines anderen Typs umgewandelt wird - in Ihrem Fall von Array Employeezu Array von Int:

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

let ids = array.map { $0.id }
Antonio
quelle
1
Das ist, was das maptut - es transformiert ein Array von Employeein ein Array von Int, gefüllt mit dem idFeld. Das entspricht der Aussage "Extrahiere das ID-Feld aus allen Instanzen von Employeeund füge sie in ein Array ein"
Antonio
4
@Isuru, diese Antwort macht genau das, was Sie wollen. Es wird ein neues Array erstellt, das idsalle idWerte aus dem Array von Employees aufruft. Beachten Sie, dass das ursprüngliche Array intakt bleibt.
Vacawama
2
Sieht aus wie in Swift 2 Beta die richtige Syntax wärearray.map( { $0.id })
TotoroTotoro
10
Wenn Sie eine Option verwenden, stellen Sie sicher, dass Sie! es. Hat Stunden gedauert.
Chris
2
@Chris erzwungenes Auspacken ist normalerweise eine schlechte Praxis, da die App abstürzt, wenn sie gleich Null ist. Verwenden Sie es nur, wenn es unbedingt erforderlich ist, und bevorzugen Sie stattdessen eine optionale Bindung (oder ein anderes "weiches" Auspacken)
Antonio,
80

Swift 5 bietet viele Möglichkeiten, um ein Array von Eigenschaftswerten aus einem Array ähnlicher Objekte abzurufen. Je nach Ihren Anforderungen können Sie eines der sechs folgenden Playground-Codebeispiele auswählen , um Ihr Problem zu lösen.


1. mapMethode verwenden

Mit Swift Sequencehaben protokollkonforme Typen eine map(_:)Methode. Der folgende Beispielcode zeigt die Verwendung:

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. forSchleife verwenden

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. whileSchleife verwenden

Beachten Sie, dass bei Swift hinter den Kulissen eine forSchleife nur eine whileSchleife über sequenceden Iterator eines S ist ( weitere Informationen finden Sie unter IteratorProtocol ).

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. Mit einem structdass Konform IteratorProtocolund SequenceProtokollen

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. Verwenden der CollectionProtokollerweiterung undAnyIterator

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. Verwendung KVC und NSArray‚s value(forKeyPath:)Verfahren

Beachten Sie, dass dieses Beispiel class Employeevon erben muss 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]
}
Imanou Petit
quelle
5
riesig ... Soweit ich weiß, vollständige Liste möglicher Ansätze
Injectios