在 Swift 的陣列中,我們難免會對陣列進行排序,而我們如何帶入多個條件,就針對要排序的陣列進行排序呢?其實只要在 Sequence 寫一個小小的擴充,就可以達到囉!
![[Swift] 如何一次進行多個條件的排序? 1 swift 1](https://www.inote.tw/wp-content/uploads/2020/02/swift-1.png)
首先,我們先寫以下的擴充,而這個擴充的參數,則是帶入多個條件。
extension Sequence {
mutating func sorted(by predicates: ((Element, Element) -> Bool)...) -> [Element] {
return sorted(by:) { lhs, rhs in
for predicate in predicates {
if predicate(lhs, rhs) { return true }
if predicate(rhs, lhs) { return false }
}
return false
}
}
mutating func sorted(by predicates: [(Element, Element) -> Bool]) -> [Element] {
return sorted(by:) { lhs, rhs in
for predicate in predicates {
if predicate(lhs, rhs) { return true }
if predicate(rhs, lhs) { return false }
}
return false
}
}
}
同樣的,我們來舉例,假設我們有下列的程式碼。而我們預設產生 6 位學生。
struct Student {
var name: String
var grade: Int
var age: Int
}
let a = Student(name: "Alex", grade: 75, age: 13)
let b = Student(name: "Banana", grade: 90, age: 15)
let c = Student(name: "Cat", grade: 85, age: 14)
let d = Student(name: "Dog", grade: 80, age: 13)
let e = Student(name: "elephant", grade: 75, age: 14)
let f = Student(name: "flower", grade: 90, age: 15)
var students = [a,b,c,d,e,f]
接下來,我們要對學生進行排序,當 Grade 或是 Age 一樣時,我們選擇名字從小到大來排序。
typealias Order = (Student, Student) -> Bool
let sortByAgeDesc: Order = { $0.age > $1.age }
let sortByGradeDesc: Order = { $0.grade > $1.grade }
let sortByName: Order = { $0.name < $1.name }
let sortByAgeAsc: Order = { $0.age < $1.age }
let sortByGradeAsc: Order = { $0.grade < $1.grade }
這時,如果只是要排序 Grade,並依降冪排序的話,我們只要寫這樣的程式就好了。
students.sorted(by: [sortByGradeDesc, sortByName])
print(students)
/// print [{name "Banana", grade 90, age 15},
/// {name "flower", grade 90, age 15},
/// {name "Cat", grade 85, age 14},
/// {name "Dog", grade 80, age 13},
/// {name "Alex", grade 75, age 13},
/// {name "elephant", grade 75, age 14}]
由於我們在擴充有用到 varArgs,也因此可以寫成這樣,也是一樣的意思的喔!
students.sorted(by: sortByGradeDesc, sortByName)
print(students)
/// print [{name "Banana", grade 90, age 15},
/// {name "flower", grade 90, age 15},
/// {name "Cat", grade 85, age 14},
/// {name "Dog", grade 80, age 13},
/// {name "Alex", grade 75, age 13},
/// {name "elephant", grade 75, age 14}]