Birden çok kriterin karşılaştırmasını yapmak için tuple kullanma
Birden çok ölçüte göre sıralama gerçekleştirmenin gerçekten basit bir yolu (yani, bir karşılaştırmaya göre sıralama ve eşdeğer ise, sonra başka bir karşılaştırma) tuple kullanmaktır , çünkü <
ve >
işleçleri sözlükbilimsel karşılaştırmalar yapan aşırı yüklemelere sahiptir.
public func < <A : Comparable, B : Comparable>(lhs: (A, B), rhs: (A, B)) -> Bool
Örneğin:
struct Contact {
var firstName: String
var lastName: String
}
var contacts = [
Contact(firstName: "Leonard", lastName: "Charleson"),
Contact(firstName: "Michael", lastName: "Webb"),
Contact(firstName: "Charles", lastName: "Alexson"),
Contact(firstName: "Michael", lastName: "Elexson"),
Contact(firstName: "Alex", lastName: "Elexson"),
]
contacts.sort {
($0.lastName, $0.firstName) <
($1.lastName, $1.firstName)
}
print(contacts)
Bu, önce elemanların lastName
özelliklerini karşılaştıracaktır . Eşit değillerse, sıralama düzeni <
onlarla karşılaştırmaya dayalı olacaktır . Bunlar ise olan eşit, daha sonra, başlığın elemanların bir sonraki çift üzerine hareket karşılaştırarak yani edecek firstName
özellikleri.
Standart kütüphane, 2 ila 6 elemanlı tuplelar sağlar <
ve >
aşırı yükler.
Farklı özellikler için farklı sıralama düzenleri istiyorsanız, demetlerdeki öğeleri kolayca değiştirebilirsiniz:
contacts.sort {
($1.lastName, $0.firstName) <
($0.lastName, $1.firstName)
}
Bu şimdi lastName
azalan, sonra firstName
artan şekilde sıralanacaktır.
sort(by:)
Birden çok yüklem alan bir aşırı yük tanımlama
Koleksiyonları map
kapatma ve SortDescriptors ile Sıralama konusundaki tartışmadan esinlenilen başka bir seçenek, özel bir aşırı yüklemeyi tanımlamak sort(by:)
ve sorted(by:)
birden çok yüklemle ilgilenmek olabilir - burada her bir yüklem, öğelerin sırasına karar vermek için dikkate alınır.
extension MutableCollection where Self : RandomAccessCollection {
mutating func sort(
by firstPredicate: (Element, Element) -> Bool,
_ secondPredicate: (Element, Element) -> Bool,
_ otherPredicates: ((Element, Element) -> Bool)...
) {
sort(by:) { lhs, rhs in
if firstPredicate(lhs, rhs) { return true }
if firstPredicate(rhs, lhs) { return false }
if secondPredicate(lhs, rhs) { return true }
if secondPredicate(rhs, lhs) { return false }
for predicate in otherPredicates {
if predicate(lhs, rhs) { return true }
if predicate(rhs, lhs) { return false }
}
return false
}
}
}
extension Sequence {
mutating func sorted(
by firstPredicate: (Element, Element) -> Bool,
_ secondPredicate: (Element, Element) -> Bool,
_ otherPredicates: ((Element, Element) -> Bool)...
) -> [Element] {
return sorted(by:) { lhs, rhs in
if firstPredicate(lhs, rhs) { return true }
if firstPredicate(rhs, lhs) { return false }
if secondPredicate(lhs, rhs) { return true }
if secondPredicate(rhs, lhs) { return false }
for predicate in otherPredicates {
if predicate(lhs, rhs) { return true }
if predicate(rhs, lhs) { return false }
}
return false
}
}
}
( secondPredicate:
Parametre talihsizdir, ancak mevcut sort(by:)
aşırı yük ile belirsizlikler yaratmamak için gereklidir )
Bu daha sonra şunu söylememizi sağlar ( contacts
önceki diziyi kullanarak ):
contacts.sort(by:
{ $0.lastName > $1.lastName },
{ $0.firstName < $1.firstName }
)
print(contacts)
let sortedContacts = contacts.sorted(by:
{ $0.lastName > $1.lastName },
{ $0.firstName < $1.firstName }
)
Çağrı sitesi, tuple varyantı kadar özlü olmasa da, neyin karşılaştırıldığı ve hangi sırayla yapıldığına dair ek netlik kazanırsınız.
Uygun Comparable
Eğer gibi düzenli sonra bu türde karşılaştırmaları yapıyor gibi gidiyoruz @AMomchilov & @appzYourLife önermek, sen uyabilir Contact
için 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)
}
}
Ve şimdi sadece sort()
artan bir düzen için arayın :
contacts.sort()
veya sort(by: >)
azalan bir sıra için:
contacts.sort(by: >)
İç içe bir türde özel sıralama siparişleri tanımlama
Kullanmak istediğiniz başka sıralama emirleriniz varsa, bunları iç içe bir türde tanımlayabilirsiniz:
extension Contact {
enum Comparison {
static let firstLastAscending: (Contact, Contact) -> Bool = {
return ($0.firstName, $0.lastName) <
($1.firstName, $1.lastName)
}
}
}
ve sonra şu şekilde arayın:
contacts.sort(by: Contact.Comparison.firstLastAscending)