Obtenir un tableau de valeurs de propriété à partir d'un tableau d'objets

113

Il y a une classe appelée 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
    }
}

Et j'ai une panoplie d' Employeeobjets. Ce dont j'ai maintenant besoin, c'est d'extraire le ids de tous ces objets de ce tableau dans un nouveau tableau.

J'ai également trouvé cette question similaire . Mais c'est en Objective-C donc il est utilisé valueForKeyPathpour accomplir cela.

Comment puis-je faire cela dans Swift?

Isuru
la source

Réponses:

234

Vous pouvez utiliser la mapméthode, qui transforme un tableau d'un certain type en un tableau d'un autre type - dans votre cas, du tableau de Employeeau tableau de 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
la source
1
C'est ce que mapfait le - il transforme un tableau de Employeeen un tableau de Int, rempli avec le idchamp. Ce qui équivaut à dire "extraire le champ id de toutes les instances de Employeeet les mettre dans un tableau"
Antonio
4
@Isuru, cette réponse fait exactement ce que vous voulez. Il crée un nouveau tableau appelé idsde toutes les idvaleurs du tableau de Employees. Notez qu'il laisse le tableau d'origine intact.
vacawama
2
On dirait que dans Swift 2 beta, la syntaxe correcte seraitarray.map( { $0.id })
TotoroTotoro
10
si vous utilisez une option, assurez-vous que vous! il. Cela m'a pris des heures.
Chris
2
Le déballage forcé @Chris est généralement une mauvaise pratique, car s'il est nul, l'application se bloquera. Utilisez-le uniquement lorsque cela est strictement nécessaire, et préférez la reliure facultative (ou tout autre déballage "souple") à la place
Antonio
81

Swift 5 offre de nombreuses façons d'obtenir un tableau de valeurs de propriété à partir d'un tableau d'objets similaires. Selon vos besoins, vous pouvez choisir l'un des six exemples de code Playground suivants pour résoudre votre problème.


1. Utilisation de la mapméthode

Avec Swift, les types conformes au Sequenceprotocole ont une map(_:)méthode. L'exemple de code suivant montre comment l'utiliser:

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. Utilisation de la forboucle

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. Utilisation de la whileboucle

Notez qu'avec Swift, dans les coulisses, une forboucle n'est qu'une whileboucle sur sequencel'itérateur d'un (voir IteratorProtocol pour plus de détails).

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. Utilisation d'un structconforme aux protocoles IteratorProtocoletSequence

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. Utilisation de l' Collectionextension de protocole etAnyIterator

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. Utilisation de NSArrayla value(forKeyPath:)méthode KVC et

Notez que cet exemple nécessite class Employeed'hériter de 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
la source
5
énorme ... C'est autant que je comprends la liste complète des approches possibles
Injectios