2017-10-10 75 views
0

深入研究函數式編程和整體快速我被多種處理方式所淹沒。在這種情況下,我希望struct採用Comparable,但可以有條件地切換哪些屬性在重載操作符中使用。如何有條件地在協議擴展方法實現之間切換?

比方說,我有以下的,一個快速排序(從和合Yahel的Wenderlich FP教程),延長任何類似陣列,這將很容易適應我CollectionStudent小號

struct Student { 
    let name: String 
    let age: Int 
    let grades: Double 
} 

extension Student: Comparable { 
    static func <(lhs: Student, rhs: Student) -> Bool { 
     return lhs.grades < rhs.grades 
    } 
    static func ==(lhs: Student, rhs: Student) -> Bool { 
     return lhs.grades == rhs.grades 
    } 
} 

extension Array where Element: Comparable { 
    func quickSorted() -> [Element] { 
     if self.count > 1 { 
      let (pivot, remaining) = (self[0], dropFirst()) 
      let lhs = remaining.filter{ $0 <= pivot } 
      let rhs = remaining.filter{ $0 > pivot } 
      return lhs.quickSorted() as [Element] + pivot + rhs.quickSorted() 
      } 
     return self 
     } 
    } 
} 

//Omitted, create a bunch of Students 
//let bingoLittle = Student(name: "BingoLittle", age: 23, grades: 93.4) 
let myStudentDirectory = [bingoLittle, studentB, ... StudentN] 
let sortedStudentDirectory = myStudentDirectory.quickSorted() 

但是,我想什麼下一步是決定結構將按名稱,等級還是年齡排序,最好不用碰這個不錯的快速排序功能。

  1. quicksort應該變成一個通用函數嗎?
  2. 我應該看看類型限制嗎?
  3. 我應該在Student中擁有一個屬性,它應該排序哪個屬性的枚舉?看起來很醜。
  4. 我應該有一個類似於quickSorted(by: .name)的quickSorted?它似乎不太適用於數組擴展。

回答

0

有幾種方法可以解決這個:

1)使用本機排序功能,這讓你指定一個比較封閉,從而提供了更多的靈活性,不要求你的結構是可比:

let sortedStudentDirectory = myStudentDirectory.sorted{ $0.grade < $1.grade } 

// 
// This would be my recommendation given that it is standard and 
// it is unlikely that the quicksorted() method would outperform it. 
// 

2)修改quicksorted()函數以讓它與閉合工作:

extension Array 
{ 
    func quickSorted<T:Comparable>(_ property:@escaping (Element)->T) -> [Element] 
    { 
     guard self.count > 1 else { return self } 
     let (pivot, remaining) = (property(self[0]), dropFirst()) 
     let lhs = remaining.filter{ property($0) <= pivot } 
     let rhs = remaining.filter{ property($0) > pivot } 
     return lhs.quickSorted(property) as [Element] + self[0] + rhs.quickSorted(property) 
    } 
} 

let sortedStudentDirectory = myStudentDirectory.quickSorted{$0.grades} 

// this one also avoids making the struct Comparable. 
// you could implement it like the standard sort with a comparison 
// closure instead of merely a property accessor so that descending 
// sort order and multi-field sorting can be supported. 

3)一個靜態變量添加到您的學生結構要告訴你的比較操作該場使用和使用quicksorted()函數之前設置靜態變量

struct Student 
{ 
    enum SortOrder { case name, age, grades } 
    static var sortOrder = .grades 
    let name: String 
    let age: Int 
    let grades: Double 
} 

extension Student: Comparable 
{ 
    static func <(lhs: Student, rhs: Student) -> Bool 
    { 
     switch Student.sortOrder 
     { 
      case .grades : return lhs.grades < rhs.grades 
      case .age : return lhs.age < rhs.age 
      default  : return lhs.name < rhs.name 
     } 
    } 

    static func ==(lhs: Student, rhs: Student) -> Bool 
    { 
     switch Student.sortOrder 
     { 
      case .grades : return lhs.grades == rhs.grades 
      case .age : return lhs.age == rhs.age 
      default  : return lhs.name == rhs.name 
     } 
    } 
} 

Student.sortOrder = .grades 
let sortedStudentDirectory = myStudentDirectory.quickSorted() 

這最後一個是非常糟糕和錯誤因爲它會影響結構上的其他比較操作,可能不打算對它進行排序(特別是對於==運算符)。它也不是線程安全的。