Obtenha uma matriz de valores de propriedade de uma matriz de objeto

113

Há uma classe chamada 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 eu tenho uma série de Employeeobjetos. O que eu preciso agora é extrair os ids de todos os objetos dessa matriz em uma nova matriz.

Eu também encontrei essa pergunta semelhante . Mas está em Objective-C, então é usado valueForKeyPathpara fazer isso.

Como posso fazer isso no Swift?

Isuru
fonte

Respostas:

234

Você pode usar o mapmétodo, que transforma uma matriz de um determinado tipo em uma matriz de outro tipo - no seu caso, de matriz de Employeea matriz 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
fonte
1
Isso é o que o mapfaz - ele transforma um array de Employeeem um array de Int, preenchido com o idcampo. O que equivale a dizer "extraia o campo id de todas as instâncias de Employeee coloque-os em uma matriz"
Antonio
4
@Isuru, esta resposta faz exatamente o que você deseja. Ele cria uma nova matriz chamada idsde todos os idvalores da matriz de Employees. Observe que ele deixa a matriz original intacta.
vacawama de
2
Parece que no Swift 2 beta a sintaxe correta seriaarray.map( { $0.id })
TotoroTotoro
10
se você estiver usando um opcional, certifique-se de! isto. Demorou horas.
Chris
2
O desembrulhamento forçado do @Chris geralmente é uma prática ruim, porque se for nulo, o aplicativo travará. Use-o apenas quando estritamente necessário e prefira a encadernação opcional (ou qualquer outro desembrulhamento "suave")
Antonio
81

O Swift 5 oferece muitas maneiras de obter uma matriz de valores de propriedade a partir de uma matriz de objetos semelhantes. De acordo com suas necessidades, você pode escolher um dos seis seguintes exemplos de código do Playground para resolver seu problema.


1. mapMétodo de uso

Com o Swift, os tipos que estão em conformidade com o Sequenceprotocolo têm um map(_:)método. O código de exemplo a seguir mostra como usá-lo:

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. Usando 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. Usando whileloop

Observe que com o Swift, nos bastidores, um forloop é apenas um whileloop sobre um sequenceiterador (consulte IteratorProtocol para obter mais detalhes).

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. Usando um structque está em conformidade com IteratorProtocole Sequenceprotocolos

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. Usando Collectionextensão de protocolo 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. Usando NSArrayo value(forKeyPath:)método KVC e de

Observe que este exemplo requer class Employeepara herdar 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
fonte
5
enorme ... Tanto quanto eu entendo, lista completa de abordagens possíveis
Injectios