如何有条件地在协议扩展方法实现之间切换?

问题描述:

深入研究函数式编程和整体快速我被多种处理方式所淹没。在这种情况下,我希望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?它似乎不太适用于数组扩展。

有几种方法可以解决这个:

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() 

这最后一个是非常糟糕和错误因为它会影响结构上的其他比较操作,可能不打算对它进行排序(特别是对于==运算符)。它也不是线程安全的。