Is there a function that I can use to iterate over an array and have both index and element, like Python's enumerate
?
for index, element in enumerate(list):
...
Yes. As of Swift 3.0, if you need the index for each element along with its value, you can use the enumerated()
method to iterate over the array. It returns a sequence of pairs composed of the index and the value for each item in the array. For example:
for (index, element) in list.enumerated() {
print("Item \(index): \(element)")
}
Before Swift 3.0 and after Swift 2.0, the function was called enumerate()
:
for (index, element) in list.enumerate() {
print("Item \(index): \(element)")
}
Prior to Swift 2.0, enumerate
was a global function.
for (index, element) in enumerate(list) {
println("Item \(index): \(element)")
}
Swift 5 provides a method called enumerated()
for Array
. enumerated()
has the following declaration:
func enumerated() -> EnumeratedSequence<Array<Element>>
Returns a sequence of pairs (n, x), where n represents a consecutive integer starting at zero and x represents an element of the sequence.
In the simplest cases, you may use enumerated()
with a for loop. For example:
let list = ["Car", "Bike", "Plane", "Boat"]
for (index, element) in list.enumerated() {
print(index, ":", element)
}
/*
prints:
0 : Car
1 : Bike
2 : Plane
3 : Boat
*/
Note however that you're not limited to use enumerated()
with a for loop. In fact, if you plan to use enumerated()
with a for loop for something similar to the following code, you're doing it wrong:
let list = [Int](1...5)
var arrayOfTuples = [(Int, Int)]()
for (index, element) in list.enumerated() {
arrayOfTuples += [(index, element)]
}
print(arrayOfTuples) // prints [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
A swiftier way to do this is:
let list = [Int](1...5)
let arrayOfTuples = Array(list.enumerated())
print(arrayOfTuples) // prints [(offset: 0, element: 1), (offset: 1, element: 2), (offset: 2, element: 3), (offset: 3, element: 4), (offset: 4, element: 5)]
As an alternative, you may also use enumerated()
with map
:
let list = [Int](1...5)
let arrayOfDictionaries = list.enumerated().map { (a, b) in return [a : b] }
print(arrayOfDictionaries) // prints [[0: 1], [1: 2], [2: 3], [3: 4], [4: 5]]
Moreover, although it has some limitations, forEach
can be a good replacement to a for loop:
let list = [Int](1...5)
list.reversed().enumerated().forEach { print($0, ":", $1) }
/*
prints:
0 : 5
1 : 4
2 : 3
3 : 2
4 : 1
*/
By using enumerated()
and makeIterator()
, you can even iterate manually on your Array
. For example:
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
var generator = ["Car", "Bike", "Plane", "Boat"].enumerated().makeIterator()
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.setTitle("Tap", for: .normal)
button.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
button.addTarget(self, action: #selector(iterate(_:)), for: .touchUpInside)
view.addSubview(button)
}
@objc func iterate(_ sender: UIButton) {
let tuple = generator.next()
print(String(describing: tuple))
}
}
PlaygroundPage.current.liveView = ViewController()
/*
Optional((offset: 0, element: "Car"))
Optional((offset: 1, element: "Bike"))
Optional((offset: 2, element: "Plane"))
Optional((offset: 3, element: "Boat"))
nil
nil
nil
*/
enumerate
?
Starting with Swift 2, the enumerate function needs to be called on the collection like so:
for (index, element) in list.enumerate() {
print("Item \(index): \(element)")
}
I found this answer while looking for a way to do that with a Dictionary, and it turns out it's quite easy to adapt it, just pass a tuple for the element.
// Swift 2
var list = ["a": 1, "b": 2]
for (index, (letter, value)) in list.enumerate() {
print("Item \(index): \(letter) \(value)")
}
For completeness you can simply iterate over your array indices and use subscript to access the element at the corresponding index:
let list = [100,200,300,400,500]
for index in list.indices {
print("Element at:", index, " Value:", list[index])
}
Using forEach
list.indices.forEach {
print("Element at:", $0, " Value:", list[$0])
}
Using collection enumerated()
method. Note that it returns a collection of tuples with the offset
and the element
:
for item in list.enumerated() {
print("Element at:", item.offset, " Value:", item.element)
}
using forEach:
list.enumerated().forEach {
print("Element at:", $0.offset, " Value:", $0.element)
}
Those will print
Element at: 0 Value: 100 Element at: 1 Value: 200 Element at: 2 Value: 300 Element at: 3 Value: 400 Element at: 4 Value: 500
If you need the array index (not the offset) and its element you can extend Collection and create your own method to get the indexed elements:
extension Collection {
func indexedElements(body: ((index: Index, element: Element)) throws -> Void) rethrows {
var index = startIndex
for element in self {
try body((index,element))
formIndex(after: &index)
}
}
}
Another possible implementation as suggested by Alex is to zip the collection indices with its elements:
extension Collection {
func indexedElements(body: ((index: Index, element: Element)) throws -> Void) rethrows {
for element in zip(indices, self) { try body(element) }
}
var indexedElements: Zip2Sequence<Indices, Self> { zip(indices, self) }
}
Testing:
let list = ["100","200","300","400","500"]
// You can iterate the index and its elements using a closure
list.dropFirst(2).indexedElements {
print("Index:", $0.index, "Element:", $0.element)
}
// or using a for loop
for (index, element) in list.indexedElements {
print("Index:", index, "Element:", element)
}
This will p[rint
Index: 2 Element: 300 Index: 3 Element: 400 Index: 4 Element: 500 Index: 0 Element: 100 Index: 1 Element: 200 Index: 2 Element: 300 Index: 3 Element: 400 Index: 4 Element: 500
enumeratedIndices
by looping over with zip(self.indices, self)
for element in zip(indices, self) { try body(element) }
. Btw I don't like the naming I chose, indexedElements
might describe better what it does
for
loop works, but also zip(self.indices, self) .forEach(body)
forEach
does a for loop behind the scenes. I prefer to keep it plain simple github.com/apple/swift/blob/master/stdlib/public/core/… @inlinable public func forEach( _ body: (Element) throws -> Void ) rethrows { for element in self { try body(element) } } }
Swift 5.x:
I personally prefer using the forEach
method:
list.enumerated().forEach { (index, element) in
...
}
You can also use the short version:
list.enumerated().forEach { print("index: \($0.0), value: \($0.1)") }
You can simply use loop of enumeration to get your desired result:
Swift 2:
for (index, element) in elements.enumerate() {
print("\(index): \(element)")
}
Swift 3 & 4:
for (index, element) in elements.enumerated() {
print("\(index): \(element)")
}
Or you can simply go through a for loop to get the same result:
for index in 0..<elements.count {
let element = elements[index]
print("\(index): \(element)")
}
Hope it helps.
Basic enumerate
for (index, element) in arrayOfValues.enumerate() {
// do something useful
}
or with Swift 3...
for (index, element) in arrayOfValues.enumerated() {
// do something useful
}
Enumerate, Filter and Map
However, I most often use enumerate in combination with map or filter. For example with operating on a couple of arrays.
In this array I wanted to filter odd or even indexed elements and convert them from Ints to Doubles. So enumerate()
gets you index and the element, then filter checks the index, and finally to get rid of the resulting tuple I map it to just the element.
let evens = arrayOfValues.enumerate().filter({
(index: Int, element: Int) -> Bool in
return index % 2 == 0
}).map({ (_: Int, element: Int) -> Double in
return Double(element)
})
let odds = arrayOfValues.enumerate().filter({
(index: Int, element: Int) -> Bool in
return index % 2 != 0
}).map({ (_: Int, element: Int) -> Double in
return Double(element)
})
Swift 5.x:
let list = [0, 1, 2, 3, 4, 5]
list.enumerated().forEach { (index, value) in
print("index: \(index), value: \(value)")
}
Or,
list.enumerated().forEach {
print("index: \($0.offset), value: \($0.element)")
}
Or,
for (index, value) in list.enumerated() {
print("index: \(index), value: \(value)")
}
Using .enumerate()
works, but it does not provide the true index of the element; it only provides an Int beginning with 0 and incrementing by 1 for each successive element. This is usually irrelevant, but there is the potential for unexpected behavior when used with the ArraySlice
type. Take the following code:
let a = ["a", "b", "c", "d", "e"]
a.indices //=> 0..<5
let aSlice = a[1..<4] //=> ArraySlice with ["b", "c", "d"]
aSlice.indices //=> 1..<4
var test = [Int: String]()
for (index, element) in aSlice.enumerate() {
test[index] = element
}
test //=> [0: "b", 1: "c", 2: "d"] // indices presented as 0..<3, but they are actually 1..<4
test[0] == aSlice[0] // ERROR: out of bounds
It's a somewhat contrived example, and it's not a common issue in practice but still I think it's worth knowing this can happen.
it does not actually provide the true index of the element; it only provides an Int beginning with 0 and incrementing by 1 for each successive element
Yes, that's why it's called enumerate. Also, slice is not array, so no surprise it behaves differently. There's no bug here - everything is by design. :)
filter
first?
Starting with Swift 3, it is
for (index, element) in list.enumerated() {
print("Item \(index): \(element)")
}
This is the Formula of loop of Enumeration:
for (index, value) in shoppingList.enumerate() {
print("Item \(index + 1): \(value)")
}
for more detail you can check Here.
For those who want to use forEach
.
Swift 4
extension Array {
func forEachWithIndex(_ body: (Int, Element) throws -> Void) rethrows {
try zip((startIndex ..< endIndex), self).forEach(body)
}
}
Or
array.enumerated().forEach { ... }
Xcode 8 and Swift 3: Array can be enumerated using tempArray.enumerated()
Example:
var someStrs = [String]()
someStrs.append("Apple")
someStrs.append("Amazon")
someStrs += ["Google"]
for (index, item) in someStrs.enumerated()
{
print("Value at index = \(index) is \(item)").
}
console:
Value at index = 0 is Apple
Value at index = 1 is Amazon
Value at index = 2 is Google
For what you are wanting to do, you should use the enumerated()
method on your Array:
for (index, element) in list.enumerated() {
print("\(index) - \(element)")
}
Use .enumerated() like this in functional programming:
list.enumerated().forEach { print($0.offset, $0.element) }
In iOS 8.0/Swift 4.0+
You can use forEach
As per the Apple docs:
Returns a sequence of pairs (n, x), where n represents a consecutive integer starting at zero and x represents an element of the sequence.
let numberWords = ["one", "two", "three"]
numberWords.enumerated().forEach { (key, value) in
print("Key: \(key) - Value: \(value)")
}
We called enumerate function to implements this. like
for (index, element) in array.enumerate() {
index is indexposition of array
element is element of array
}
Success story sharing
enumerating
for Swift 4. Exciting!for (index, element) in
when usingenumerated
is misleading. should befor (offset, element) in