การใช้ tuples เพื่อทำการเปรียบเทียบเกณฑ์ต่างๆ
วิธีง่ายๆในการจัดเรียงตามเกณฑ์หลายเกณฑ์ (เช่นการเรียงลำดับตามการเปรียบเทียบหนึ่งรายการและหากเทียบเท่าแล้วโดยการเปรียบเทียบอีกแบบหนึ่ง) คือการใช้tuplesเนื่องจากตัวดำเนินการ<
และ>
มีโอเวอร์โหลดสำหรับพวกเขาที่ทำการเปรียบเทียบพจนานุกรม
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: "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)
สิ่งนี้จะเปรียบเทียบlastName
คุณสมบัติขององค์ประกอบก่อน ถ้าไม่เท่ากันลำดับการจัดเรียงจะขึ้นอยู่กับการ<
เปรียบเทียบกับพวกเขา หากพวกเขามีความเท่าเทียมกันแล้วมันจะย้ายไปยังคู่ต่อไปขององค์ประกอบใน tuple คือการเปรียบเทียบfirstName
คุณสมบัติ
ไลบรารีมาตรฐานจัดเตรียม<
และ>
โอเวอร์โหลดสำหรับทูเปิล 2 ถึง 6 องค์ประกอบ
หากคุณต้องการจัดเรียงลำดับที่แตกต่างกันสำหรับคุณสมบัติที่แตกต่างกันคุณสามารถสลับองค์ประกอบในสิ่งต่อไปนี้:
contacts.sort {
($1.lastName, $0.firstName) <
($0.lastName, $1.firstName)
}
ตอนนี้จะเรียงลำดับจากlastName
มากไปหาน้อยแล้วจากfirstName
น้อยไปมาก
การกำหนดsort(by:)
โอเวอร์โหลดที่ใช้เพรดิเคตหลายตัว
แรงบันดาลใจจากการอภิปรายเกี่ยวกับการเรียงลำดับคอลเลกชันที่มีการmap
ปิดและ SortDescriptorsอีกทางเลือกหนึ่งคือการกำหนดโอเวอร์โหลดที่กำหนดเองsort(by:)
และsorted(by:)
เกี่ยวข้องกับเพรดิเคตหลายตัวซึ่งแต่ละเพรดิเคตจะได้รับการพิจารณาเพื่อตัดสินใจลำดับขององค์ประกอบ
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:
พารามิเตอร์เป็นสิ่งที่ไม่ดี แต่จำเป็นเพื่อหลีกเลี่ยงการสร้างความคลุมเครือกับการsort(by:)
โอเวอร์โหลดที่มีอยู่)
สิ่งนี้ช่วยให้เราสามารถพูด (โดยใช้contacts
อาร์เรย์จากก่อนหน้านี้):
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 }
)
แม้ว่าไซต์การโทรจะไม่รัดกุมเท่ากับตัวแปรทูเพิล แต่คุณจะได้รับความชัดเจนเพิ่มเติมจากสิ่งที่กำลังเปรียบเทียบและลำดับ
สอดคล้องกับ Comparable
หากคุณกำลังจะทำเหล่านี้ชนิดของการเปรียบเทียบอย่างสม่ำเสมอแล้วเป็น@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()
ลำดับจากน้อยไปมาก:
contacts.sort()
หรือsort(by: >)
ลำดับจากมากไปหาน้อย:
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)