[Swift] 如何一次進行多個條件的排序?

Swift 的陣列中,我們難免會對陣列進行排序,而我們如何帶入多個條件,就針對要排序的陣列進行排序呢?其實只要在 Sequence 寫一個小小的擴充,就可以達到囉!

swift 1

首先,我們先寫以下的擴充,而這個擴充的參數,則是帶入多個條件。

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}]
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments