2016-08-27 4 views
2

Ich versuche, die folgende Funktion in eine generische Erweiterung für 2D-Arrays zu transformieren.Swift 2D Array Generische Erweiterung - Problem Zugriff auf 2. Dimension

Ich bin speziell ratlos, wie Sie die Einschränkungen angeben, damit ich auf die zweite Dimension zugreifen kann. Hier ist ein gescheiterter Versuch:

extension Array where Element: Collection, Element.Iterator.Element: Collection 
{ 
    private func rotate() 
    { 
    let count = self[0].count // Element.IndexDistance instead of Int 

    // Expression type 'Array<Element>' is ambiguous without more context 
    var returnValue = Array(repeating: Element, count: 11) 
    for index in 0 ..< count // Element.IndexDistance instead of Int 
    { 
     returnValue[index] = self.map { $0[index] }.reversed() 
    } 
    return returnValue 
    } 
} 

Antwort

3

Das Problem ist, dass der Compiler nicht weiß, dass Ihre Erweiterung für 2D-Arrays ist - er weiß nur, dass es für Arrays von Sammlungen ist. Daher sind die zugehörigen Typen IndexDistance und Index nicht notwendigerweise Int.

Die Lösung ist daher Ihre Erweiterung zu beschränken, so dass die Element ‚s IndexDistance und Index vom Typ sind Int. Auf diese Weise können Sie den Bereich bilden 0..<count, wie count jetzt vom Typ sein Int (IndexDistance) - und Sie werden die Elemente innerhalb der map(_:) mit Int s zu SUBSCRIPT fähig sein (als der Index eine Index erwartet).

(Dies wird trivial sein, wenn concrete same-type requirements tun werden unterstützt, wie Sie einfach die Element einschränken könnte ein Array, dies ist jedoch noch nicht möglich. Sein)

Sie sollten auch, dass Ihre Constraint Element.Iterator.Element: Collection beachten ist falsch, da dies die Erweiterung auf 3D-Arrays von Sammlungen einschränkt (Ein Array, in dem das Element eine Sammlung ist, wobei die Elemente dieser Sammlung eine Sammlung sind).

Schließlich kann man ein typealias zu repräsentieren den ‚inneres Element‘ Typen des 2D-Arrays definieren müssen, da derzeit Swift some limitations when working with nested types directly hat, zum Beispiel wenn eine leeren 2D-Arrays dieses Typs zu schaffen.

Daher ist eine funktionierende Version der aktuellen Methode würde wie folgt aussehen:

extension Array where Element: Collection, Element.Index == Int, Element.IndexDistance == Int { 

    private func rotate() -> [[Element.Iterator.Element]] { 

     typealias InnerElement = Element.Iterator.Element 

     // in the case of an empty array, simply return an empty array 
     if self.isEmpty { return [] } 
     let length = self[0].count 

     var returnValue = [[InnerElement]](repeating: [InnerElement](), count: length) 
     for index in 0..<length { 
      returnValue[index] = self.map{ $0[index] }.reversed() 
     } 
     return returnValue 
    } 
} 

die, wie @MartinR points out below, erheblich vereinfacht eine verschachtelte map(_:) unter Verwendung, wodurch die Notwendigkeit eines typealias wie wir nicht sein könnten länger brauchen ein 'Ergebnis' Array zu erstellen:

private func rotate() -> [[Element.Iterator.Element]] { 

    if self.isEmpty { return [] } 
    let length = self[0].count 

    return (0..<length).map { index in 
     self.map { $0[index] }.reversed() 
    } 
} 

Obwohl zu beachten, dass der Einschränkungs von y unsere Erweiterung, nur mit Int Indizes zu arbeiten, ist nicht unbedingt notwendig (macht aber keinen praktischen Unterschied, da Sie nur mit 2D-Arrays arbeiten möchten). Eine andere Alternative besteht darin, direkt über die indices der inneren Sammlung zu iterieren.

Um dies zu tun, geben Sie einfach Ihre Erweiterung beschränken müssen, so dass die Indices innere Sammlung Element s von der gleichen Art wie die Index der Sammlung haben (im Falle eines Array ist Indices ein CountableRange<Int>):

extension Array where Element: Collection, Element.Indices.Iterator.Element == Element.Index { 
    private func rotate() -> [[Element.Iterator.Element]] { 

     if self.isEmpty { return [] } 

     return self[0].indices.map { index in 
      self.map { $0[index] }.reversed() 
     } 
    } 
} 
+0

Brilliant + Vielen Dank für die wertvolle Erklärung. – AfricanSwift

+1

Sie können das vereinfachen, um (0 ..

+0

Danke Martin ... – AfricanSwift