2014-07-07 4 views
18

Ich möchte Array-Klasse erweitern, so dass es wissen kann, ob es sortiert ist (aufsteigend) oder nicht. Ich möchte eine berechnete Eigenschaft namens isSorted hinzufügen. Wie kann ich die Elemente des Arrays als vergleichbar bezeichnen?Array erweitern, um zu prüfen, ob es in Swift sortiert ist?

Meine aktuelle Implementierung in Spielplatz

extension Array { 
    var isSorted: Bool { 
    for i in 1..self.count { 
     if self[i-1] > self[i] { return false } 
    } 
    return true 
    } 
} 

// The way I want to get the computed property 
[1, 1, 2, 3, 4, 5, 6, 7, 8].isSorted //= true 
[2, 1, 3, 8, 5, 6, 7, 4, 8].isSorted //= false 

Der FehlerCould not find an overload for '>' that accepts the supplied arguments

Natürlich, ich habe immer noch einen Fehler, da Swift nicht weiß, wie die Elemente miteinander zu vergleichen. Wie kann ich diese Erweiterung in Swift implementieren? Oder mache ich hier etwas falsch?

+0

möglich duplicate of [Wie implementiert man flatten als Erweiterung auf einem Array ohne Typ Casting?] (Http://stackoverflow.com/questions/24564249/how-to-implement-flatten-as-an-extension-on -an-array-ohne-type-casting) – Sebastian

+3

Sie können 'Array ' nicht erweitern, aber Sie können eine Funktion implementieren, die auf 'Array ' arbeitet. Werfen Sie einen Blick auf http://StackOverflow.com/A/24565627/1489997 – Sebastian

+0

@Sebastian Ich denke, der Link, den Sie gaben, ist ganz anders als meine Absicht. Es ist ziemlich einfach, Kategorien für diese Art von Dingen in obj-c zu erstellen, also dachte ich, dass es in Swift so trivial sein sollte. –

Antwort

22

Die alternative Lösung zu einer freien Funktion ist, was Swift eingebauten in Array.sort und Array.sorted Methoden zu tun tun, und verlangen, dass Sie einen geeigneten Komparator an die Methode übergeben:

extension Array { 
    func isSorted(isOrderedBefore: (T, T) -> Bool) -> Bool { 
     for i in 1..<self.count { 
      if !isOrderedBefore(self[i-1], self[i]) { 
       return false 
      } 
     } 
     return true 
    } 
} 

[1, 5, 3].isSorted(<) // false 
[1, 5, 10].isSorted(<) // true 
[3.5, 2.1, -5.4].isSorted(>) // true 
+0

Beachten Sie, dass dies für das Beispiel in der Frage tatsächlich fehlschlägt: '[1, 1, 2, 3, 4, 5, 6, 7, 8] .isSorted (<)', da wiederholte Werte nicht behandelt werden. – nschum

+0

Ich denke, du willst 'if! IsOrderedBefore (self [i-1], self [i])' to 'wenn isOrderedBefore (self [i], self [i-1])' das Problem beheben, auf das hingewiesen wird nschum. – AmigoNico

+1

Vorsicht, diese Lösung würde mit leeren Arrays abstürzen. Ich würde einen Wächter hinzufügen, der überprüft, dass es kein leeres Array ist. – juancazalla

7

Sie haben ein Problem mit Swifts Generika, die nicht so gelöst werden können, wie Sie es gerade mögen (vielleicht in einer zukünftigen Swift-Version). Siehe auch Swift Generics issue.

Derzeit benötigen Sie eine Funktion (zum Beispiel im globalen Bereich) zu definieren:

func isSorted<T: Comparable>(array: Array<T>) -> Bool { 
    for i in 1..<array.count { 
     if array[i-1] > array[i] { 
      return false 
     } 
    } 

    return true 
} 

let i = [1, 2, 3] 
let j = [2, 1, 3] 
let k = [UIView(), UIView()] 
println(isSorted(i)) // Prints "true" 
println(isSorted(j)) // Prints "false" 
println(isSorted(k)) // Error: Missing argument for parameter #2 in call 

Die Fehlermeldung irreführend ist, IMHO, da der tatsächliche Fehler ist etwas wie „UIView nicht Erfüllen Sie die Typ-Constraint Comparable ".

+0

Ich bin immer noch mit dieser Art von Fällen in Swift verwechselt. Sie müssen sich noch von der Laufzeitflexibilität von obj-c an die Strenge der Swift-Syntax anpassen (Optionale, Generika usw.). Ich denke, dass meine Absicht in Swift nicht die richtige Denkweise ist. –

+0

Beide haben ihre Up- und Downside, und natürlich machen beide bestimmte Muster einfacher/"natürlicher" als die anderen. Die meisten von uns werden einige Zeit brauchen, um zu lernen, Swift-Funktionen bestmöglich zu nutzen. – DarkDust

20

In Swift 2.0 können Sie jetzt Protokolle erweitern!

extension CollectionType where Generator.Element: Comparable { 

    public var isSorted: Bool { 

     var previousIndex = startIndex 
     var currentIndex = startIndex.successor() 

     while currentIndex != endIndex { 

      if self[previousIndex] > self[currentIndex] { 
       return false 
      } 

      previousIndex = currentIndex 
      currentIndex = currentIndex.successor() 
     } 

     return true 
    } 

} 

[1, 2, 3, 4].isSorted // true 
["a", "b", "c", "e"].isSorted // true 
["b", "a", "c", "e"].isSorted // false 
[/* Anything not implementing `Comparable` */].isSorted // <~~ Type-error 

Beachten Sie, dass, weil wir Indexable.Index anstelle eines einfachen Int als Index verwenden wir stattdessen eine while-Schleife verwenden müssen, die ein bisschen weniger schön und klar aussieht.

+0

Und für Swift 3 wird 'Generator' zu' Iterator' und 'someIndex.successor()' wird 'self.index (nach: someIndex)' – markedwardmurray

1

Die flexibelste Lösung für mich ist eine Kombination aus NSAddict und Wes Campaignes Antwort. I.e. kombinieren den Vorteil, Protokolle erweitern zu können und Komparatorfunktionen als Argumente zu übergeben. Dies beseitigt die Einschränkungen sowohl für die Verwendung nur mit Arrays als auch für die Beschränkung auf Elemente, die dem Protokoll Comparable entsprechen.

extension CollectionType 
{ 
    func isSorted(isOrderedBefore: (Generator.Element, Generator.Element) -> Bool) -> Bool 
    { 
     var previousIndex = startIndex 
     var currentIndex = startIndex.successor() 

     while currentIndex != endIndex 
     { 
      if isOrderedBefore(self[previousIndex], self[currentIndex]) == false 
      { 
       return false 
      } 

      previousIndex = currentIndex 
      currentIndex = currentIndex.successor() 
     } 

     return true 
    } 
} 

Dies kann auf jede Collection Art und Sortierkriterien verwendet werden können nach Ihren Bedürfnissen definiert werden.

+1

Und für Swift 3 Ersetzen Sie 'someIndex.successor()' durch 'self.index (nach: someIndex)' – markedwardmurray

Verwandte Themen