Reputation: 13301
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):
...
Upvotes: 972
Views: 695565
Reputation: 12373
It's critical to note that Apple now does guarantee that the order is "correct"
https://developer.apple.com/documentation/swift/array/foreach(_:)
.enumerated().forEach { print("\($0.offset) \($0.element)") }
Upvotes: 1
Reputation: 2446
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
Upvotes: 5
Reputation: 2571
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)")
}
Upvotes: 6
Reputation: 1411
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)")
}
Upvotes: 58
Reputation: 549
Use .enumerated() like this in functional programming:
list.enumerated().forEach { print($0.offset, $0.element) }
Upvotes: 6
Reputation: 859
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)") }
Upvotes: 35
Reputation: 77
We called enumerate function to implements this. like
for (index, element) in array.enumerate() {
index is indexposition of array
element is element of array
}
Upvotes: -1
Reputation: 236488
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
Upvotes: 39
Reputation: 92569
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
*/
Upvotes: 163
Reputation: 392
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)")
}
Upvotes: 7
Reputation: 1225
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
Upvotes: 7
Reputation: 2362
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 { ... }
Upvotes: 7
Reputation: 2034
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.
Upvotes: 25
Reputation: 56372
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)")
}
Upvotes: 1984
Reputation: 22245
for (index, element) in arrayOfValues.enumerate() {
// do something useful
}
or with Swift 3...
for (index, element) in arrayOfValues.enumerated() {
// do something useful
}
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)
})
Upvotes: 19
Reputation: 11504
Starting with Swift 3, it is
for (index, element) in list.enumerated() {
print("Item \(index): \(element)")
}
Upvotes: 12
Reputation: 289
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.
Upvotes: 14
Reputation: 17787
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)")
}
Upvotes: 54
Reputation: 528
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.
Upvotes: 10
Reputation: 3171
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)")
}
Upvotes: 60