2016-07-16 4 views
3

ループモードでコレクションを無限に反復するイテレータを探しています。そのため、コレクションの終了インデックスに達すると、イテレータは開始インデックスにある要素を返す必要があります。ループモードでコレクションを無限に反復するカスタムイテレータ

次の解決策はうまくいくようですが、より良い方法で作成できることを願っています。

public struct LoopIterator<T: Collection>: IteratorProtocol { 

    private let collection: T 
    private var startIndexOffset: T.IndexDistance 

    public init(collection: T) { 
     self.collection = collection 
     startIndexOffset = 0 
    } 

    public mutating func next() -> T.Iterator.Element? { 
     guard !collection.isEmpty else { 
     return nil 
     } 
     let index = collection.index(collection.startIndex, offsetBy: startIndexOffset) 
     startIndexOffset += T.IndexDistance(1) 
     if startIndexOffset >= collection.count { 
     startIndexOffset = 0 
     } 
     return collection[index] 
    } 
} 

extension Array { 
    func makeLoopIterator() -> LoopIterator<Array> { 
     return LoopIterator(collection: self) 
    } 
} 

// Testing... 
// Will print: 1, 2, 3, 1, 2, 3 
var it = [1, 2, 3].makeLoopIterator() 
for _ in 0..<6 { 
    print(it.next()) 
} 

カスタムイテレータを実行するのは正しい方法ですか?何が改善できるのか?

ありがとうございます!

+1

将来的には、**コードレビュー**スタック交換のために、作業コードの改善に関する質問がおそらく適しています。 http://codereview.stackexchange.com/ –

+1

IMO、codereview.seは、それ自体がほとんど一般的ではなく、明示的に検索される可能性の低いコードのレビューに最適です(つまり、コードではなくベストプラクティスが重要です)。 )。この質問は一般的に興味深いコードについてのもので、幅広い関心のあるトピック(スウィフト3インデックスの正しい使用法)について具体的に触れており、今後検索される可能性があります。ポスターをコードに含めなかった場合、彼らは確かに「あなたは何を試しましたか?コメント。彼らがコードを含んでいれば、codereviewにそれらをリダイレクトすることは不公平に思えます。 –

答えて

6

(使用している)Swift 3では、インデックスはコレクション自体によって進められます。次のようにそれを使用すると、これを簡略化することができます。

public struct LoopIterator<Base: Collection>: IteratorProtocol { 

    private let collection: Base 
    private var index: Base.Index 

    public init(collection: Base) { 
     self.collection = collection 
     self.index = collection.startIndex 
    } 

    public mutating func next() -> Base.Iterator.Element? { 
     guard !collection.isEmpty else { 
      return nil 
     } 

     let result = collection[index] 
     collection.formIndex(after: &index) // (*) See discussion below 
     if index == collection.endIndex { 
      index = collection.startIndex 
     } 
     return result 
    } 
} 

今、私たちは、単に前方にインデックスを移動し、それが今終わりを指している場合、最初にそれをリセットします。 countまたはIndexDistanceの必要はありません。

ここでは、Iteratorが任意のコレクション(したがって任意のインデックス)で動作するため、やや不明瞭なケース(具体的にはAnyIndex)のパフォーマンスを向上させるために使用しています。より単純なバージョンはindex = collection.index(after: index)であり、それはほとんどの場合より良いかもしれません。

スウィフト3インデックスのすべての詳細については、SE-0065を参照してください。

関連する問題