Pobierz tablicę wartości właściwości z tablicy obiektów

113

Jest klasa o nazwie 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
    }
}

Mam tablicę Employeeobiektów. Teraz potrzebuję wyodrębnić ids wszystkich tych obiektów w tej tablicy do nowej tablicy.

Znalazłem też to podobne pytanie . Ale jest w Objective-C, więc używa go valueForKeyPathdo osiągnięcia tego.

Jak mogę to zrobić w Swift?

Isuru
źródło

Odpowiedzi:

234

Możesz skorzystać z mapmetody, która przekształci tablicę określonego typu w tablicę innego typu - w twoim przypadku z tablicy Employeedo tablicy 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
źródło
1
To właśnie maprobi - przekształca tablicę w Employeetablicę Intwypełnioną idpolem. Co jest równoznaczne z powiedzeniem „wyodrębnij pole id ze wszystkich instancji Employeei umieść je w tablicy”
Antonio,
4
@Isuru, ta odpowiedź robi dokładnie to, czego chcesz. Tworzy nową tablicę o nazwie idswszystkich idwartości z tablicy Employees. Uwaga, pozostawia oryginalną tablicę nienaruszoną.
vacawama
2
Wygląda na to, że w wersji beta Swift 2 poprawna składnia byłabyarray.map( { $0.id })
TotoroTotoro
10
jeśli używasz opcjonalnego, upewnij się! to. Zajęło mi to godziny.
Chris
2
Wymuszone rozpakowywanie @Chris jest zwykle złą praktyką, ponieważ jeśli nie, spowoduje to awarię aplikacji. Używaj go tylko wtedy, gdy jest to ściśle wymagane i zamiast tego wolisz opcjonalne wiązanie (lub jakiekolwiek inne „miękkie” rozpakowywanie)
Antonio
81

Swift 5 oferuje wiele sposobów uzyskiwania tablicy wartości właściwości z tablicy podobnych obiektów. W zależności od potrzeb możesz wybrać jeden z sześciu poniższych przykładów kodu Playground, aby rozwiązać problem.


1. Za pomocą mapmetody

W języku Swift typy zgodne z Sequenceprotokołem mają map(_:)metodę. Poniższy przykładowy kod pokazuje, jak go używać:

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. Korzystanie z forpętli

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. Korzystanie z whilepętli

Zauważ, że w Swift, za kulisami, forpętla jest po prostu whilepętlą nad sequenceiteratorem (zobacz IteratorProtocol po więcej szczegółów).

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. Używanie structzgodnego z protokołami IteratorProtocoliSequence

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. Korzystanie z Collectionrozszerzenia protokołu iAnyIterator

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. Używanie kvc and NSArray„s value(forKeyPath:)metody

Zauważ, że ten przykład wymaga class Employeedziedziczenia z 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
źródło
5
ogromny ... To, o ile rozumiem, pełna lista możliwych podejść
Injectios