очень простой способ выполнения своего рода по нескольким критериям (например, сортировка по одному сравнения, и если эквивалентны, то другим сравнения) является использование кортежи, как <
и >
Операторы имеют перегрузки для них, которые выполняют лексикографические сравнения.
/// Returns a Boolean value indicating whether the first tuple is ordered
/// before the second in a lexicographical ordering.
///
/// Given two tuples `(a1, a2, ..., aN)` and `(b1, b2, ..., bN)`, the first
/// tuple is before the second tuple if and only if
/// `a1 < b1` or (`a1 == b1` and
/// `(a2, ..., aN) < (b2, ..., bN)`).
public func < <A : Comparable, B : Comparable>(lhs: (A, B), rhs: (A, B)) -> Bool
Например:
struct Contact {
var firstName: String
var lastName: String
}
var contacts = [
Contact(firstName: "Charlie", lastName: "Webb"),
Contact(firstName: "Alex", lastName: "Elexson"),
Contact(firstName: "Charles", lastName: "Webb"),
Contact(firstName: "Alex", lastName: "Alexson")
]
// in Swift 2.x, sortInPlace(_:)
contacts.sort {
($0.lastName, $0.firstName) <
($1.lastName, $1.firstName)
}
print(contacts)
// [
// Contact(firstName: "Alex", lastName: "Alexson"),
// Contact(firstName: "Alex", lastName: "Elexson"),
// Contact(firstName: "Charles", lastName: "Webb"),
// Contact(firstName: "Charlie", lastName: "Webb")
// ]
Это сравнение элементов lastName
свойства первого. Если они не равны, порядок сортировки будет основан на сравнении <
. Если они равны, то он переместится на следующую пару элементов в кортеже, сравнив свойства firstName
.
Стандартная библиотека предоставляет <
и >
перегрузки для кортежей от 2 до 6 элементов.
Если вы хотите различные заказы сортировки для различных свойств, вы можете просто поменять местами элементы в кортежах:
contacts.sort {
($1.lastName, $0.firstName) <
($0.lastName, $1.firstName)
}
// [
// Contact(firstName: "Charles", lastName: "Webb"),
// Contact(firstName: "Charlie", lastName: "Webb"),
// Contact(firstName: "Alex", lastName: "Elexson"),
// Contact(firstName: "Alex", lastName: "Alexson")
// ]
Это теперь будет сортировать по убыванию lastName
, затем firstName
по возрастанию.
Если вы собираетесь делать такого рода сравнения регулярно, то, как @AMomchilov & @appzYourLife предложить, вы можете соответствовать Contact
к Comparable
:
extension Contact : Comparable {
static func == (lhs: Contact, rhs: Contact) -> Bool {
return (lhs.firstName, lhs.lastName) ==
(rhs.firstName, rhs.lastName)
}
static func < (lhs: Contact, rhs: Contact) -> Bool {
return (lhs.lastName, lhs.firstName) <
(rhs.lastName, rhs.firstName)
}
}
А теперь просто позвоните sort()
для возрастающем порядке:
// ascending
contacts.sort()
или sort(by: >)
для убывающего порядка:
// descending
contacts.sort(by: >)
Если у вас есть другие порядки сортировки, которые вы хотите использовать, вы можете определить их в гнездовой типа:
extension Contact {
enum Comparison {
static let firstLastAscending: (Contact, Contact) -> Bool = {
return ($0.firstName, $0.lastName) <
($1.firstName, $1.lastName)
}
}
}
, а затем просто называют как:
contacts.sort(by: Contact.Comparison.firstLastAscending)
Сделайте это точно так же, как вы только что сказали! Ваш код внутри фигурных скобок должен сказать: «Если фамилии совпадают, то сортируйте по имени, иначе сортируйте по имени». – matt
Я вижу, что здесь есть несколько кодов: 1) «Контакт», вероятно, не должен наследовать от «NSObject», 2) «Контакт», вероятно, должен быть структурой, а 3) 'firstName' и' lastName', вероятно, не должен быть неявно развернутые варианты. – Alexander
@AMomchilov Нет причин предполагать, что Contact должен быть структурой, потому что вы не знаете, использует ли остальная часть своего кода ссылочную семантику в использовании экземпляров этого кода. –