How to find index of list item in Swift?
As swift is in some regards more functional than object-oriented (and Arrays are structs, not objects), use the function "find" to operate on the array, which returns an optional value, so be prepared to handle a nil value:
let arr:Array = ["a","b","c"]find(arr, "c")! // 2find(arr, "d") // nil
Use firstIndex
and lastIndex
- depending on whether you are looking for the first or last index of the item:
let arr = ["a","b","c","a"]let indexOfA = arr.firstIndex(of: "a") // 0let indexOfB = arr.lastIndex(of: "a") // 3
tl;dr:
For classes, you might be looking for:
let index = someArray.firstIndex{$0 === someObject}
Full answer:
I think it's worth mentioning that with reference types (class
) you might want to perform an identity comparison, in which case you just need to use the ===
identity operator in the predicate closure:
Swift 5, Swift 4.2:
let person1 = Person(name: "John")let person2 = Person(name: "Sue")let person3 = Person(name: "Maria")let person4 = Person(name: "Loner")let people = [person1, person2, person3]let indexOfPerson1 = people.firstIndex{$0 === person1} // 0let indexOfPerson2 = people.firstIndex{$0 === person2} // 1let indexOfPerson3 = people.firstIndex{$0 === person3} // 2let indexOfPerson4 = people.firstIndex{$0 === person4} // nil
Note that the above syntax uses trailing closures syntax, and is equivalent to:
let indexOfPerson1 = people.firstIndex(where: {$0 === person1})
Swift 4 / Swift 3 - the function used to be called index
Swift 2 - the function used to be called indexOf
* Note the relevant and useful comment by paulbailey about class
types that implement Equatable
, where you need to consider whether you should be comparing using ===
(identity operator) or ==
(equality operator). If you decide to match using ==
, then you can simply use the method suggested by others (people.firstIndex(of: person1)
).
You can filter
an array with a closure:
var myList = [1, 2, 3, 4]var filtered = myList.filter { $0 == 3 } // <= returns [3]
And you can count an array:
filtered.count // <= returns 1
So you can determine if an array includes your element by combining these:
myList.filter { $0 == 3 }.count > 0 // <= returns true if the array includes 3
If you want to find the position, I don't see fancy way, but you can certainly do it like this:
var found: Int? // <= will hold the index if it was found, or else will be nilfor i in (0..x.count) { if x[i] == 3 { found = i }}
EDIT
While we're at it, for a fun exercise let's extend Array
to have a find
method:
extension Array { func find(includedElement: T -> Bool) -> Int? { for (idx, element) in enumerate(self) { if includedElement(element) { return idx } } return nil }}
Now we can do this:
myList.find { $0 == 3 }// returns the index position of 3 or nil if not found