2016-07-09 44 views
2

我想迭代一個任意的Swift集合並獲取元素及其索引。在Swift中使用索引迭代集合的正確和慣用方法?

基本上替代:

for (idx, el) in collection.enumerate() { 
    print("element at \(idx) is \(el)") 
} 

但讓我真正的通用指標,而不僅僅是連續整數從0開始。

當然,該解決方案將是一個通用的一部分函數可以接受任何類型的集合,否則它們之間的差異不會很重要。

有沒有更好的方式比像下面的天真循環?

var idx = collection.startIndex, endIdx = collection.endIndex 
while idx < endIdx { 
    let el = collection[idx] 
    print("element at \(idx) is \(el)") 
    idx = idx.successor() 
} 

寫作看起來相當容易出錯。我知道我可以將該代碼轉換爲代碼片段,但如果可能的話,我希望找到更簡潔,更具地道性的解決方案。

+0

從我的測試idx.dynamicType爲int,但你說的通用指標我失去了什麼? –

+0

@AliKıran:這取決於收藏。數組有整數索引,但字符串例如有一個特殊的String.CharacterView.Index類型。同樣,集合的索引不需要從零開始(例如數組切片)。 –

+0

我希望鏈接到「重複」可以解決您的問題。否則,讓我知道,我會重新打開這個問題。 –

回答

1

對於任何集合,indices屬性返回一系列有效的 索引。來遍歷索引和相應的元件 並聯可以使用zip()

for (idx, el) in zip(collection.indices, collection) { 
    print(idx, el) 
} 

實施例用於陣列切片:

let a = ["a", "b", "c", "d", "e", "f"] 
let slice = a[2 ..< 5] 

for (idx, el) in zip(slice.indices, slice) { 
    print("element at \(idx) is \(el)") 
} 

輸出:

 
element at 2 is c 
element at 3 is d 
element at 4 is e 

可以定義一個爲此目的的自定義擴展方法 (取自How to enumerate a slice using the original indices?):

// Swift 2: 
extension CollectionType { 
    func indexEnumerate() -> AnySequence<(index: Index, element: Generator.Element)> { 
     return AnySequence(zip(indices, self)) 
    } 
} 

// Swift 3: 
extension Collection { 
    func indexEnumerate() -> AnySequence<(Indices.Iterator.Element, Iterator.Element)> { 
     return AnySequence(zip(indices, self)) 
    } 
} 

一個字符圖示例:

let chars = "az".characters 
for (idx, el) in chars.indexEnumerate() { 
    print("element at \(idx) is \(el)") 
} 

輸出:

 
element at 0 is a 
element at 1 is 
element at 3 is 
element at 7 is z 
+0

爲什麼'chars'例子的索引是0,1,3,7而不是0,1,2,3? – dantiston

+1

@dantiston:因爲字符串索引內部引用UTF-16代碼點。但你不應該關心這些數字。如果您使用正確的方法(如advancedBy,distanceTo)來對索引進行操作,則一切都按預期工作。 –

相關問題