2017-10-10 1 views
0

In funktionale Programmierung und swift overall Ich bin überwältigt von mehreren Möglichkeiten, Dinge zu tun. In diesem Fall möchte ich struct haben, das Comparable annimmt, aber kann bedingt schalten, welche Eigenschaften in den überladenen Operatoren verwendet werden.Wie wird zwischen Implementierungen der Protokollerweiterungsmethode bedingt umgeschaltet?

Lassen Sie uns sagen, dass ich die folgende, einen quicksort (von Niv Yahel des Wenderlich FP-Tutorial), eine vergleichbare Anordnung erstrecken, die leicht meine Collection von Student s

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

beherbergen wird aber, was ich möchte Ein nächster Schritt ist die Entscheidung, ob die Struktur nach Namen, Noten oder Alter sortiert wird, vorzugsweise ohne diese nette Quicksort-Funktion zu berühren.

  1. Sollte Quicksort in eine generische Funktion umgewandelt werden?
  2. Sollte ich Typ Einschränkungen betrachten?
  3. Sollte ich eine Eigenschaft in Student haben, die eine enum welcher Eigenschaft sollte es sortieren? Scheint hässlich.
  4. Sollte ich eine QuickSorte haben, die so ähnlich ist wie quickSorted(by: .name)? Es scheint nicht mehr gut zu einer Array-Erweiterung zu passen.

Antwort

0

Es gibt mehrere Möglichkeiten, dies zu nähern:

1) verwenden, um die nativen Sortierfunktionen, die Ihnen einen Verschluss für den Vergleich angeben lassen und bietet somit viel mehr Flexibilität und erfordert nicht, dass Ihre Struktur vergleichbar sein :

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) die quicksorted() Funktion ändern, um es mit einem Verschluss arbeiten zu lassen:

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) Fügen Sie eine statische Variable auf Ihre Studenten struct Ihrem Vergleichsoperator zu sagen, welches Feld die statische Variable zu verwenden und vor der quicksorted() Funktion

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

Dieses letzt man verwendet, ist ziemlich schlecht und Fehler anfällig, da dies Auswirkungen auf andere Vergleichsoperationen in der Struktur hat, die möglicherweise nicht beabsichtigt ist, sie zu sortieren (insbesondere für den Operator ==). Es ist auch nicht threadsicher.

Verwandte Themen