950

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):
    ...
Vukašin Manojlović
  • 3,717
  • 3
  • 19
  • 31
thinker3
  • 12,771
  • 5
  • 30
  • 36

19 Answers19

1950

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)")
}
Cezar
  • 55,636
  • 19
  • 86
  • 87
  • 3
    Although it seems like a tuple, in Swift 1.2 - not sure about 2.0 - enumerate returns an EnumerateSequence struct. – nstein Jul 03 '15 at 12:52
  • 2
    @Leviathlon noticeable or measurable performance overhead that will matter? No. – Dan Rosenstark May 19 '16 at 15:09
  • is getting access to the index the only benefit of using `enumerate`? – mfaani Dec 05 '16 at 15:51
  • 35
    Maybe they'll change to the gerund, `enumerating` for Swift 4. Exciting! – Dan Rosenstark Mar 22 '17 at 14:40
  • @Honey you are not getting any index there. You are getting the offset which is different. It works for arrays but If you enumerate a slice don't use the offset to subscript your collection. Use the collection indices. Not all collections starts at index zero. – Leo Dabus Mar 01 '19 at 19:55
  • 3
    @Honey `for (index, element) in` when using `enumerated` is misleading. should be `for (offset, element) in` – Leo Dabus Mar 01 '19 at 20:01
  • 2
    Do we hold a sweepstakes as to who can guess what it'll change to next. This damn language just can't sit still lol – Shayne Mar 08 '19 at 00:46
156

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
 */
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
59

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)")
}
Cezar
  • 55,636
  • 19
  • 86
  • 87
Ricky
  • 3,101
  • 1
  • 25
  • 33
54

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)")
}
rounak
  • 9,217
  • 3
  • 42
  • 59
Arnaud
  • 17,268
  • 9
  • 65
  • 83
43

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)")
}
Rabel Ahmed
  • 1,131
  • 13
  • 12
35

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

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • BTW you can implement `enumeratedIndices` by looping over with `zip(self.indices, self)` – Alexander Feb 05 '20 at 23:30
  • @Alexander-ReinstateMonica `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 – Leo Dabus Feb 06 '20 at 00:18
  • Ooo I think that's a better name. Yeah, a `for` loop works, but also `zip(self.indices, self) .forEach(body)` – Alexander Feb 06 '20 at 00:25
  • @Alexander-ReinstateMonica `forEach` does a for loop behind the scenes. I prefer to keep it plain simple https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift `@inlinable public func forEach( _ body: (Element) throws -> Void ) rethrows { for element in self { try body(element) } } }` – Leo Dabus Feb 06 '20 at 00:29
  • 1
    for index in list.indices is brilliant @LeoDabus !!!!!!!!!!!!!!!! – Fattie Jan 06 '23 at 17:15
34

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)") }
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
davebcn87
  • 819
  • 7
  • 4
  • Interesting tidbit for forEach cannot return a value - Unexpected non-void return value in void function. So return the result afterwards. – Meep Apr 11 '21 at 11:38
  • 2
    You also won't be able to skip a loop if need be – CyberMew Mar 12 '22 at 04:13
24

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.

Riajur Rahman
  • 1,976
  • 19
  • 28
18

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)
                        })
Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
12

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.

Cole Campbell
  • 249
  • 3
  • 7
  • 2
    `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. :) – Eric Aya May 30 '16 at 09:28
  • 5
    True, but I never called it a bug. It just is potentially unexpected behavior that I thought was worth mentioning for those who didn't know how it could interact negatively with the ArraySlice type. – Cole Campbell May 30 '16 at 20:22
  • Are you aware of any way to get the index of the actual element - for example if using `filter` first? – Alexandre Cassagne Aug 27 '18 at 14:47
11

Starting with Swift 3, it is

for (index, element) in list.enumerated() {
  print("Item \(index): \(element)")
}
Jake Lin
  • 11,146
  • 6
  • 29
  • 40
9

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.

Dara Tith
  • 518
  • 7
  • 21
6

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
koen
  • 5,383
  • 7
  • 50
  • 89
Anil Gupta
  • 1,155
  • 1
  • 19
  • 26
6

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 { ... }
Vincent Sit
  • 2,214
  • 1
  • 24
  • 27
6

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)")
}
Ale Mohamad
  • 372
  • 4
  • 7
  • 1
    enumerated() was the magic spell I was looking for.... that fixed my 'uple pattern cannot match values of non-tuple type 'Items'' error.. THANK YOU! – marika.daboja Mar 18 '21 at 04:21
5

Use .enumerated() like this in functional programming:

list.enumerated().forEach { print($0.offset, $0.element) } 
pavelcauselov
  • 519
  • 5
  • 10
4

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)")
}
excitedmicrobe
  • 2,338
  • 1
  • 14
  • 30
2

If you for whatever reason want a more traditional looking for loop that accesses the elements in the array using their index:

let xs = ["A", "B", "C", "D"]

for i in 0 ..< xs.count {
    print("\(i) - \(xs[i])")
}

Output:

0 - A
1 - B
2 - C
3 - D
Chris
  • 2,166
  • 1
  • 24
  • 37
-1

We called enumerate function to implements this. like

    for (index, element) in array.enumerate() {
     index is indexposition of array
     element is element of array 
   }
Naqeeb
  • 1,121
  • 8
  • 25