How to get index and value from for loop in Swift

⋅ 4 min read ⋅ Swift Control Flow Array

Table of Contents

Swift has many ways to iterate over a collection of items, e.g., forEach and a for-in loop.

You will get access to each element in the collection, but not an index.

If you also want to get an index of each element, there are two ways to do it.

  1. Use indices property
  2. Use enumerated() method
  3. Use zip method with indices property

Get index with indices property

indices is an instance property of a Collection protocol. It returns indices of that collection without an element, but you can easily use that index to get an element from the collection.

let names = ["Alice", "Bob", "John"]

// 1
names.indices.forEach { index in
// 2
print("\(index): \(names[index])")
}
// 0: Alice
// 1: Bob
// 2: John

// 3
for index in names.indices {
print("\(index): \(names[index])")
}
// 0: Alice
// 1: Bob
// 2: John

We can loops over indices using forEach 1 or a for-in 3.
2 Then, you use that index from indices to get an element at that particular index, i.e., name[index].

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Get offset with enumerated method

Another way to get an index of an element in a collection is by using enumerated() method.

enumerated() returns a sequence of pairs (n, x), where:

  • n represents a consecutive integer starting at zero.
  • x represents an element of the sequence.

We can access this index and element pairs by iterate over them using forEach and a for-in loop.

let names = ["Alice", "Bob", "John"]

names.enumerated().forEach { (index, name) in
print("\(index): \(name)")
}
// 0: Alice
// 1: Bob
// 2: John

for (index, name) in names.enumerated() {
print("\(index): \(name)")
}
// 0: Alice
// 1: Bob
// 2: John

Caveat

Iterating over index and element using the enumerated() method sounds like a good choice. You get both index and element without a need to manually retrieve it like indices, but there is one thing you should know before using it.

When you enumerate a collection, the integer part of each pair is a counter for the enumerationbut is not necessarily the index of the paired value.

You can think of enumerated() doing something like this.

let names = ["Alice", "Bob", "John"]

var index = 0
for name in names {
print("\(index): \(name)")
index += 1
}

As you can see, the index is just a counter, not an index. So, it can be used as indices only in instances of zero-based, integer-indexed collections.

Example

I can give you one example for non-zero-based indexed collections.

In this example, we use the dropFirst method, which drops the first element from the collection. Then we use the result collection from dropFirst method with enumerated() and indices.

let names = ["Alice", "Bob", "John"]
let dropFirstNames = names.dropFirst()

for (index, name) in dropFirstNames.enumerated() {
print("\(index): \(name)")
}
// 0: Bob
// 1: John

for index in dropFirstNames.indices {
print("\(index): \(names[index])")
}
// 1: Bob
// 2: John

As you can see, enumerated() returns a counter of each element while indices returns a real index of the resulting array[1].

Get index using zip and indices

If you want to iterate over the elements of a collection with its indices but don't want to get it manually, you can use the zip(_:_:) function.

zip creates a sequence of pairs built out of two underlying sequences.

We zip indices sequence (names.indices) and names together.

let names = ["Alice", "Bob", "John"]
let namesWithIndex = zip(names.indices, names)

let dropFirstNames = names.dropFirst()
let dropFirstNamesWithIndex = zip(dropFirstNames.indices, dropFirstNames)

for (index, name) in namesWithIndex {
print("\(index): \(name)")
}
// 0: Alice
// 1: Bob
// 2: John

for (index, name) in dropFirstNamesWithIndex {
print("\(index): \(name)")
}
// 1: Bob
// 2: John

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Conclusion

Array.enumerated() might look like an easy choice when you want to get an index and element. But as you can see, it might not be what you are looking for if you want to use that index to reference an element in the collection since it is just a counter.

If you want to get an actual index of a collection, you must use indices or indices with zip.


  1. dropFirst returns ArraySlice. ArraySlice maintain indices of the original array. This makes the starting index for an ArraySlice instance isn’t always zero. https://developer.apple.com/documentation/swift/arrayslice ↩︎


Read more article about Swift, Control Flow, Array, or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
SwiftUI zIndex: Everything you need to know

zIndex is a modifier that controls the display order of overlapping views in SwiftUI. Let's learn how it works.

Next
For loop in SwiftUI using ForEach

When creating an app, there is a time when you want to create a repetitive view or a collection of views from an array of data. We can do that in SwiftUI with ForEach.

← Home