Отримати масив значень властивостей з масиву об’єктів


113

Там називається клас 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
    }
}

І у мене є масив Employeeоб’єктів. Що мені зараз потрібно - це витягнути ids з усіх цих об'єктів у цей масив у новий масив.

Я також знайшов подібне питання . Але він знаходиться в Objective-C, тому він використовує valueForKeyPathдля цього.

Як я можу це зробити у Swift?

Відповіді:


234

Ви можете використовувати mapметод, який перетворює масив певного типу в масив іншого типу - у вашому випадку з масиву Employeeв масив 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
Це те, що mapробить - він перетворює масив Employeeмасиву Int, заповненого idполем. Що еквівалентно вимові "витягнути поле id з усіх екземплярів Employeeі помістити їх у масив"
Антоніо

4
@Isuru, ця відповідь робить саме те, що ви хочете. Він створює новий масив, який називається idsвсіма idзначеннями з масиву Employees. Зауважте, він залишає початковий масив недоторканим.
vacawama

2
Схоже, у бета-версії Swift 2 правильним буде синтаксисarray.map( { $0.id })
TotoroTotoro,

10
якщо ви використовуєте необов’язковий, переконайтесь, що ви це. Взяв мене години.
Кріс

2
@Chris примусове розгортання зазвичай є поганою практикою, тому що, якщо нуль, це призведе до збоїв у програмі. Використовуйте його лише в тих випадках, коли це суворо вимагається, і віддайте перевагу додатковому обв'язуванню (або будь-якому іншому "м'якому" розгортанню)
Антоніо

81

Swift 5 пропонує безліч способів отримати масив значень властивості з масиву подібних об'єктів. Відповідно до ваших потреб, ви можете вибрати один із шести наступних прикладів коду для дитячої площадки, щоб вирішити свою проблему.


1. Використання mapметоду

У Swift типи, які відповідають Sequenceпротоколу, мають map(_:)метод. Наступний зразок коду показує, як його використовувати:

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. Використання forциклу

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. Використання whileциклу

Зауважте, що у Swift поза кадром forцикл - це лише whileпетля над sequenceітератором ітератора (детальніше див. 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. Використання structвідповідного IteratorProtocolта Sequenceпротоколів

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. Використання Collectionрозширення протоколу таAnyIterator

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. Використання КВЦ і NSArray«S value(forKeyPath:)метод

Зауважте, що цей приклад вимагає class Employeeуспадкування від 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
величезне ... Це, наскільки я розумію повний список можливих підходів
Injectios
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.