2016-07-16 88 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

國際海事組織,codereview.se是最適合審查代碼本身將是一般興趣不大,不可能明確搜索(即最佳做法是有趣的,而不是代碼)。這個問題是關於一個普遍有趣的代碼,特別涉及廣泛關注的主題(正確使用Swift 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 
    } 
} 

現在我們簡單地向前移動索引,如果它現在指向到底,其重置爲開頭:有了這一點,你可以按如下簡化此。不需要countIndexDistance

請注意,我在這裏使用了formIndex,因爲您的Iterator可以在任何Collection(以及任何索引)上工作,因此可以在某些不明顯的情況下(特別是在AnyIndex附近)提高性能。更簡單的版本將是index = collection.index(after: index),並且在大多數情況下可能會更好。

有關Swift 3索引的所有血統細節,請參見SE-0065