2016-08-27 10 views
2

次の関数を2D配列の一般的な拡張に変換しようとしています。Swift 2D配列汎用拡張 - 2次元へのアクセスの問題

func rotate(_ input: [[Int]]) -> [[Int]] 
{ 
    let length = input[0].count 
    var value = Array(repeating: [Int](), count: length) 
    for index in 0 ..< length 
    { 
    value[index] = input.map { $0[index] }.reversed() 
    } 
    return value 
} 

私は、制約を指定して2番目の次元にアクセスできるように指定する方法が特に困惑しています。

答えて

3

問題は、拡張機能が2D配列用であることをコンパイラーが認識していないことです。コレクションの配列用であることがわかります。したがって、関連するタイプIndexDistanceおよびIndexは必ずしもIntである必要はありません。

ソリューションは、したがって、ElementIndexDistanceIndexはタイプIntになるように、あなたの拡張機能を制限することです。これにより、範囲0..<countが形成されます。はIntIndexDistance)となり、​​の要素はInt(下付き文字はIndexとなります)で下付き文字で入力することができます。

(あなたは、単にしかし、これはまだ不可能である、ArrayするElementを制約する可能性があり、これは、concrete same-type requirementsがサポートされれば行うことは些細なことだろう。)

あなたはまた、Element.Iterator.Element: Collectionあなたの制約に注意すべきです拡張子がコレクションの3D配列(要素がコレクションであり、そのコレクションの要素がコレクションである配列)に制約されるため、正しくありません。

最後に、Swiftが現在some limitations when working with nested types directlyを持っているので、たとえばそのタイプの空の2D配列を作成するときに、typealiasを定義して、2D配列の '内部要素'タイプを表す必要があります。

したがって、あなたの現在のメソッドの作業バージョンは、次のようになります

@MartinR points out belowとして、我々がないよう typealiasの必要性を排除し、ネストされた​​を使用することによって大幅に簡略化することができ、
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 
    } 
} 

を長い「結果」のアレイを作成する必要があります。その

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

が、メモして、yの制約Intインデックスでのみ機能する拡張は厳密には必要ではありません(2D配列でこれを使用することのみを意図しているので実用的な違いはありません)。もう一つの方法は、内部コレクションのindicesを直接反復することです。

これを行うためには、あなたは、単にインナーコレクションのIndicesは(IndicesCountableRange<Int>で、Arrayの場合)コレクションのIndexと同じタイプのElement秒を持っているように、あなたの拡張を制限する必要があります。

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

貴重な説明をありがとうございます。 – AfricanSwift

+1

空の結果配列を最初に作成せずに、 'return(0 ..

+0

ありがとうマーティン... – AfricanSwift