Asked
8 years, 11 months ago
Viewed
660k times
I am trying to find an item index
by searching a list
. Does anybody know how to do that?
I see there is list.StartIndex
and list.EndIndex
but I want something like python’s list.index("text")
.
ArunPratap
4,7187 gold badges24 silver badges43 bronze badges
asked Jun 4, 2014 at 4:10
0
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")! // 2
find(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") // 0
let indexOfB = arr.lastIndex(of: "a") // 3
johndpope
4,9252 gold badges40 silver badges43 bronze badges
answered Jun 5, 2014 at 20:08
Sebastian SchuthSebastian Schuth
9,9191 gold badge20 silver badges14 bronze badges
17
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} // 0
let indexOfPerson2 = people.firstIndex{$0 === person2} // 1
let indexOfPerson3 = people.firstIndex{$0 === person3} // 2
let 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)
).
answered Oct 3, 2015 at 13:55
8
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 nil
for 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
answered Jun 4, 2014 at 4:38
gwcoffeygwcoffey
5,5511 gold badge18 silver badges20 bronze badges
7
Swift 5
func firstIndex(of element: Element) -> Int?
var alphabets = ["A", "B", "E", "D"]
Example1
let index = alphabets.firstIndex(where: {$0 == "A"})
Example2
if let i = alphabets.firstIndex(of: "E") {
alphabets[i] = "C" // i is the index
}
print(alphabets)
// Prints "["A", "B", "C", "D"]"
answered Oct 17, 2017 at 11:20
SaranjithSaranjith
11.2k4 gold badges65 silver badges120 bronze badges
1
While indexOf()
works perfectly, it only returns one index.
I was looking for an elegant way to get an array of indexes for elements which satisfy some condition.
Here is how it can be done:
Swift 3:
let array = ["apple", "dog", "log"]
let indexes = array.enumerated().filter {
$0.element.contains("og")
}.map{$0.offset}
print(indexes)
Swift 2:
let array = ["apple", "dog", "log"]
let indexes = array.enumerate().filter {
$0.element.containsString("og")
}.map{$0.index}
print(indexes)
answered Aug 16, 2016 at 13:07
Serhii YakovenkoSerhii Yakovenko
12.4k2 gold badges26 silver badges26 bronze badges
1
in Swift 4.2
.index(where:) was changed to .firstIndex(where:)
array.firstIndex(where: {$0 == "person1"})
answered Oct 16, 2019 at 7:23
In Swift 4, the firstIndex method can be used. An example of using the ==
equality operator to find an object in an array by its id
:
let index = array.firstIndex{ $0.id == object.id }
- note this solution avoids your code needing to conform to the Equitable protocol as we’re comparing the property and not the entire object
Also, a note about ==
vs ===
since many of the answers posted so far have differed in their usage:
==
is the equality operator. It checks if values are equal.===
is the identity operator. It checks whether two instances of a class point to the same memory. This is different from equality, because two objects that were created independently using the same values will be considered equal using == but not === because they are different objects. (Source)
It would be worth it to read more on these operators from Swift’s documentation.
answered Apr 15, 2021 at 12:01
DwigtDwigt
5695 silver badges16 bronze badges
For custom class, you need to implement the Equatable protocol.
import Foundation
func ==(l: MyClass, r: MyClass) -> Bool {
return l.id == r.id
}
class MyClass: Equtable {
init(id: String) {
self.msgID = id
}
let msgID: String
}
let item = MyClass(3)
let itemList = [MyClass(1), MyClass(2), item]
let idx = itemList.indexOf(item)
printl(idx)
answered Nov 16, 2015 at 6:27
ZYiOSZYiOS
5,1943 gold badges39 silver badges45 bronze badges
Just use firstIndex method.
array.firstIndex(where: { $0 == searchedItem })
answered May 25, 2020 at 17:39
erdikanikerdikanik
6549 silver badges11 bronze badges
1
Update for Swift 2:
sequence.contains(element): Returns true if a given sequence (such as
an array) contains the specified element.
Swift 1:
If you’re looking just to check if an element is contained inside an array, that is, just get a boolean indicator, use contains(sequence, element)
instead of find(array, element)
:
contains(sequence, element): Returns true if a given sequence (such as
an array) contains the specified element.
See example below:
var languages = ["Swift", "Objective-C"]
contains(languages, "Swift") == true
contains(languages, "Java") == false
contains([29, 85, 42, 96, 75], 42) == true
if (contains(languages, "Swift")) {
// Use contains in these cases, instead of find.
}
Bretsko
5782 gold badges6 silver badges20 bronze badges
answered Apr 25, 2015 at 23:44
ZorayrZorayr
23.5k7 gold badges135 silver badges126 bronze badges
Swift 4. If your array contains elements of type [String: AnyObject]. So to find the index of element use the below code
var array = [[String: AnyObject]]()// Save your data in array
let objectAtZero = array[0] // get first object
let index = (self.array as NSArray).index(of: objectAtZero)
Or If you want to found index on the basis of key from Dictionary. Here array contains Objects of Model class and I am matching id property.
let userId = 20
if let index = array.index(where: { (dict) -> Bool in
return dict.id == userId // Will found index of matched id
}) {
print("Index found")
}
OR
let storeId = Int(surveyCurrent.store_id) // Accessing model key value
indexArrUpTo = self.arrEarnUpTo.index { Int($0.store_id) == storeId }! // Array contains models and finding specific one
answered Feb 5, 2018 at 12:16
Gurjinder SinghGurjinder Singh
8,7511 gold badge63 silver badges57 bronze badges
In Swift 4, if you are traversing through your DataModel array, make sure your data model conforms to Equatable Protocol , implement the lhs=rhs method , and only then you can use “.index(of” . For example
class Photo : Equatable{
var imageURL: URL?
init(imageURL: URL){
self.imageURL = imageURL
}
static func == (lhs: Photo, rhs: Photo) -> Bool{
return lhs.imageURL == rhs.imageURL
}
}
And then,
let index = self.photos.index(of: aPhoto)
answered Sep 30, 2017 at 6:25
NaishtaNaishta
11.7k4 gold badges71 silver badges54 bronze badges
For (>= swift 4.0)
It’s rather very simple.
Consider the following Array
object.
var names: [String] = ["jack", "rose", "jill"]
In order to obtain the index of the element rose
, all you have to do is:
names.index(of: "rose") // returns 1
Note:
-
Array.index(of:)
returns anOptional<Int>
. -
nil
implies that the element isn’t present in the array. -
You might want to force-unwrap the returned value or use an
if-let
to get around the optional.
answered Feb 24, 2020 at 14:29
mzainkmzaink
2414 silver badges9 bronze badges
Swift 2.1
var array = ["0","1","2","3"]
if let index = array.indexOf("1") {
array.removeAtIndex(index)
}
print(array) // ["0","2","3"]
Swift 3
var array = ["0","1","2","3"]
if let index = array.index(of: "1") {
array.remove(at: index)
}
array.remove(at: 1)
answered Nov 9, 2015 at 10:53
Luca DavanzoLuca Davanzo
20.8k15 gold badges119 silver badges146 bronze badges
1
In Swift 2 (with Xcode 7), Array
includes an indexOf
method provided by the CollectionType
protocol. (Actually, two indexOf
methods—one that uses equality to match an argument, and another that uses a closure.)
Prior to Swift 2, there wasn’t a way for generic types like collections to provide methods for the concrete types derived from them (like arrays). So, in Swift 1.x, “index of” is a global function… And it got renamed, too, so in Swift 1.x, that global function is called find
.
It’s also possible (but not necessary) to use the indexOfObject
method from NSArray
… or any of the other, more sophisticated search meth dis from Foundation that don’t have equivalents in the Swift standard library. Just import Foundation
(or another module that transitively imports Foundation), cast your Array
to NSArray
, and you can use the many search methods on NSArray
.
Cœur
36.8k25 gold badges192 silver badges260 bronze badges
answered Jun 4, 2014 at 4:13
ricksterrickster
124k26 gold badges271 silver badges325 bronze badges
0
Any of this solution works for me
This the solution i have for Swift 4 :
let monday = Day(name: "M")
let tuesday = Day(name: "T")
let friday = Day(name: "F")
let days = [monday, tuesday, friday]
let index = days.index(where: {
//important to test with === to be sure it's the same object reference
$0 === tuesday
})
answered Jul 24, 2018 at 6:32
Kevin ABRIOUXKevin ABRIOUX
16.2k12 gold badges91 silver badges96 bronze badges
0
You can also use the functional library Dollar to do an indexOf on an array as such http://www.dollarswift.org/#indexof-indexof
$.indexOf([1, 2, 3, 1, 2, 3], value: 2)
=> 1
answered Nov 10, 2014 at 0:25
Encore PTLEncore PTL
8,03410 gold badges42 silver badges77 bronze badges
If you are still working in Swift 1.x
then try,
let testArray = ["A","B","C"]
let indexOfA = find(testArray, "A")
let indexOfB = find(testArray, "B")
let indexOfC = find(testArray, "C")
answered Jul 20, 2015 at 12:54
iCyberPauliCyberPaul
6504 silver badges15 bronze badges
For SWIFT 3 you can use a simple function
func find(objecToFind: String?) -> Int? {
for i in 0...arrayName.count {
if arrayName[i] == objectToFind {
return i
}
}
return nil
}
This will give the number position, so you can use like
arrayName.remove(at: (find(objecToFind))!)
Hope to be useful
answered Mar 3, 2017 at 6:09
MarcoMarco
712 bronze badges
0
In Swift 4/5, use “firstIndex” for find index.
let index = array.firstIndex{$0 == value}
answered Sep 9, 2019 at 8:31
Krunal PatelKrunal Patel
1,6291 gold badge14 silver badges22 bronze badges
Swift 4
For reference types:
extension Array where Array.Element: AnyObject {
func index(ofElement element: Element) -> Int? {
for (currentIndex, currentElement) in self.enumerated() {
if currentElement === element {
return currentIndex
}
}
return nil
}
}
answered Dec 21, 2017 at 10:31
MennoMenno
1,22212 silver badges23 bronze badges
In case somebody has this problem
Cannot invoke initializer for type 'Int' with an argument list of type '(Array<Element>.Index?)'
jsut do this
extension Int {
var toInt: Int {
return self
}
}
then
guard let finalIndex = index?.toInt else {
return false
}
answered Jan 23, 2020 at 1:05
Ahmed SafadiAhmed Safadi
4,33236 silver badges32 bronze badges
SWIFT 4
Let’s say you want to store a number from the array called cardButtons into cardNumber, you can do it this way:
let cardNumber = cardButtons.index(of: sender)
sender is the name of your button
answered Dec 23, 2018 at 18:48
Как найти нужный элемент в массиве на Swift? Давайте разберемся! В этом руководстве вы узнаете, как использовать различные функции для поиска совпадающих элементов в массиве.
Поиск индекса элемента в массиве вручную
Прежде чем мы углубимся в способы поиска элементов в массиве, давайте выясним, как может работать такой алгоритм. Задача проста: для массива произвольного количества элементов нам нужно найти индекс заданного значения.
Вот обзор нашего подхода:
- Перебрать каждое значение в массиве.
- Отслеживать текущий индекс, который мы проверяем.
- Сравните текущее значение со значением, которое мы ищем.
- Если появляется совпадение, вернуть текущий индекс, если нет, продолжить перебор массива.
let names = ["Ford", "Arthur", "Trillian", "Zaphod", "Marvin", "Deep Thought", "Eddie", "Slartibartfast", "Humma Kuvula"] let searchValue = "Zaphod" var currentIndex = 0 for name in names { if name == searchValue { print("Имя (name) для индекса (currentIndex)") break } currentIndex += 1 } // Имя Zaphod для индекса 3
Мы используем цикл for для перебора каждого элемента в массиве names.
- С помощью оператора if мы проверяем, совпадает ли name с searchValue.
- Если мы находим совпадение, мы выводим строку на консоль и останавливаем выполнение цикла с помощью break. Если мы этого не сделаем, цикл продолжится, даже если мы уже нашли то, что ищем.
- В конце цикла мы увеличиваем значение currentIndex на единицу. Таким образом, мы отслеживаем текущий индекс массива.
Мы можем превратить наш код в функцию:
func find(value searchValue: String, in array: [String]) -> Int? { for (index, value) in array.enumerated() { if value == searchValue { return index } } return nil }
Мы используем функцию enumerated() для получения пары индекс-значение. Таким образом, мы можем напрямую получить конкретный индекс для искомого элемента без необходимости отслеживать его самостоятельно.
Когда функция находит искомое значение, происходит выход из функции. Когда значение не может быть найдено, функция возвращает nil. Таким образом, возвращаемый тип функции – Int?
Мы можем использовать данную функцию следующим образом:
let names = ["Ford", "Arthur", "Trillian", "Zaphod", "Marvin", "Deep Thought", "Eddie", "Slartibartfast", "Humma Kuvula"] let index = find(value: "Eddie", in: names) print(index) // Optional(6)
Поиск элемента в массиве с помощью firstIndex(of:)
Самый простой способ найти элемент в массиве – использовать функцию firstIndex(of:):
if let index = names.firstIndex(of: "Marvin") { print(index) } // 4
Эта функция является универсальной, поэтому ее можно использовать независимо от типа массива.
Также мы можем заменить какое-либо значение в массиве:
if let index = names.firstIndex(of: "Zaphod") { names[index] = "Prostetnic Vogon Jeltz" }
Поскольку функция firstIndex(of:) просматривает все значения массива от первого до последнего, она всегда возвращает индекс первого найденного совпадения. Если вы хотите получить последнее совпадение в массиве, вы можете использовать функцию lastIndex(of:).
Поиск элемента в массиве с помощью firstIndex(where:)
Что делать, если вы точно не знаете, какое конкретное значение ищете? Тут нам поможет функция firstIndex(where:). Эта функция принимает замыкание в качестве параметра для поиска совпадений в массиве.
let grades = [8, 9, 10, 1, 2, 5, 3, 4, 8, 8] if let index = grades.firstIndex(where: { $0 < 7 }) { print("Первый индекс < 7 = (index)") } // 3
В приведенном выше коде мы работаем с массивом целых чисел grades. Мы хотим знать индекс первого элемента массива, который меньше 7. При этом мы знаем только то, что оно должно быть меньше 7.
Код между фигурными скобками – это замыкание, которое выполняется для каждого элемента массива, пока мы не найдем успешное совпадение, то есть выражение $0 < 7 должно вернуть true.
Мы используем опциональное связывание для извлечения опционального значения из firstIndex(where:).
Данная функция принадлежит к группе функций, которые могут выбирать элементы из массива, соответствующие заданному предикату:
- firstIndex(where:) возвращает индекс первого элемента, соответствующего предикату.
- lastIndex(where:) возвращает индекс последнего элемента, соответствующего предикату.
- contains(where:) возвращает логическое значение, указывающее, содержит ли массив элемент, соответствующий предикату.
- allSatisfy(_:) возвращает логическое значение, указывающее, все ли элементы в массиве соответствуют предикату.
- first(where:)возвращает первый элемент (не индекс) массива, который соответствует предикату.
- last(where:)возвращает последний элемент (не индекс) массива, который соответствует предикату.
Имейте в виду, что если вы хотите использовать вышеуказанные функции, элементы в вашем массиве должны соответствовать протоколу Equatable. Типы, соответствующие этому протоколу, можно сравнить с помощью оператора ==, который используется для проверки равенства двух элементов.
Поиск всех элементов в массиве с помощью all(where:)
Что, если мы хотим найти все элементы в массиве, которые бы соответствовали заданному предикату? В стандартной библиотеке Swift пока нет данной функции, но мы можем создать свою собственную.
extension Array where Element: Equatable { func all(where predicate: (Element) -> Bool) ->; [Element] { return self.compactMap { predicate($0) ? $0 : nil } } }
Объявление функции принимает параметр типа (Element) -> Bool и возвращает массив типа [Element]. Далее мы используем функцию compactMap (_ :). Эта функция применяет замыкание для каждого элемента в массиве, а также удаляет значения nil. Выражение predicate($0) ? $0 : nil вернет значение $0, когда предикат возвращает true и nil, когда будет возвращено false.
let grades = [8, 9, 10, 1, 2, 5, 3, 4, 8, 8] let goodGrades = grades.all(where: { $0 > 7 }) print(goodGrades) // [8, 9, 10, 8, 8]
To get the first index of an item in an array in Swift, use the array.firstIndex(where:) method.
For instance, let’s find the first occurrence of the string “a” in an array:
let arr = ["a", "b", "c", "b", "a"] let i1 = arr.firstIndex(where: {$0 == "a"}) print(i1!)
Output:
0
Don’t let the $0 notation confuse you.
Here is how it works:
- The firstIndex() method goes through the array of items.
- It assigns each item to variable $0 one by one.
- Then it checks if the condition holds for that item.
- When it encounters the first item that matches the condition, it returns the index (as an optional).
If you are still confused about the $0 notation, feel free to check this article.
You can apply similar logic to find an index of an array of objects.
Also, as you can see, this approach only finds the first index, not all of them.
To find out all the indexes of a specific item in an array, please continue reading.
How to Find the Index of an Object in an Array of Objects
You can use the array.firstIndex(where:) method to find an object that meets a specific criterion.
This is useful when you have an array of objects with properties based on which you are searching.
For example, let’s create a class that represents a Student.
class Student { let name: String init(name: String) { self.name = name } }
Next, let’s create an array of students:
let student1 = Student(name: "Alice") let student2 = Student(name: "Bob") let student3 = Student(name: "Charlie") let students = [student1, student2, student3]
Now, let’s use the array.firstIndex(where:) method to find the position of a student called Bob:
let bob_pos = students.firstIndex(where: {$0.name == "Bob"}) print("Bob is at position (bob_pos!).")
Output:
Bob is at position 1.
But what if you have more than one element you want to find?
In this case, using the firsIndex() is not enough as it only returns the first index.
Instead, you have to group, filter, and map the array in a specific way.
In the next section, we are going to take a look at how.
How to Find All Indexes of a Value in an Array in Swift
So far you’ve learned how to find the first index of a specific element in an array in Swift.
But what if you want to find them all?
To find all the indexes of a value in the Swift array:
- Group each array element with an index.
- Filter the resulting array based on a criterion.
- Map the result to only contain the indexes.
Here is the idea in code:
arr.enumerated().filter{ $0.element == something }.map{ $0.offset }
For example, let’s find the indexes of the letter “a” in the array:
let arr = ["a", "b", "a", "b", "a"] let idxs = arr.enumerated().filter{ $0.element == "a" }.map{ $0.offset } print(idxs)
If you have an array of objects, you can use a similar approach.
For example, let’s find out all the Student object whose name is “Bob” in the array:
class Student { let name: String init(name: String) { self.name = name } } let students = [ Student(name: "Alice"), Student(name: "Bob"), Student(name: "Charlie"), Student(name: "Bob") ] // Find indexes of student Bob: let indexes = students.enumerated().filter{ $0.element.name == "Bob" }.map{ $0.offset } print(indexes)
How Does It Work?
Please, have a look at this piece of code:
arr.enumerated().filter{ $0.element == something }.map{ $0.offset }
There are three things that you may be unfamiliar with:
- The enumerated() method.
- The filter() method with $0.
- The map() method with $0.
Let me briefly explain what these do.
- The enumerated() method converts an array of items to an array of (index, item) pairs. Swift calls these (offset, element) pairs.
- The filter() method filters out all the elements of the (offset, element) pairs where the element does not meet a criterion.
- The map() method converts the resulting array of (offset, element) pairs to an array of offsets.
Let’s take a step-by-step look at the process of finding all elements that equal to “a”:
1. Enumerate the array with the enumerated() method.
let idxs = arr.enumerated() for pair in idxs { print(pair) }
Output:
(offset: 0, element: "a") (offset: 1, element: "b") (offset: 2, element: "a") (offset: 3, element: "b") (offset: 4, element: "a")
2. Filter out all the pairs where the element is not “a”:
let idxs = arr.enumerated().filter{ $0.element == "a" } for pair in idxs { print(pair) }
Now we are left with pairs that only contain elements that are “a”:
(offset: 0, element: "a") (offset: 2, element: "a") (offset: 4, element: "a")
3. Transform pairs to an array of indexes
let idxs = arr.enumerated().filter{ $0.element == "a" }.map { $0.offset } for pair in idxs { print(pair) }
Output:
0 2 4
And there you have it!
Conclusion
Today you learned how to get the index of the first element of an array that matches a criterion.
arr.firstIndex(where: {$0 == something})
You also learned how to get all the indexes of array items that meet the criterion.
arr.enumerated().filter{ $0.element == something }.map{ $0.offset }
Thanks for reading. I hope you find it useful.
Happy coding!
Further Reading
50 Swift Interview Questions
iOS Development Tips
About the Author
-
I’m an entrepreneur and a blogger from Finland. My goal is to make coding and tech easier for you with comprehensive guides and reviews.
Recent Posts
Is there a method called indexof or something similar?
var array = ["Jason", "Charles", "David"]
indexOf(array, "Jason") // Should return 0
asked Jun 8, 2014 at 10:47
0
EDIT: As of Swift 3.0, you should use the .index(where:)
method instead and follow the change in the Swift 2.0 edit below.
EDIT: As of Swift 2.0, you should use the indexOf
method instead. It too returns nil
or the first index of its argument.
if let i = array.indexOf("Jason") {
print("Jason is at index (i)")
} else {
print("Jason isn't in the array")
}
Use the find
function. It returns either nil
(if the value isn’t found) or the first index of the value in the array.
if let i = find(array, "Jason") {
println("Jason is at index (i)")
} else {
println("Jason isn't in the array")
}
John Difool
5,5145 gold badges43 silver badges79 bronze badges
answered Jun 8, 2014 at 10:50
nathannathan
5,4563 gold badges26 silver badges24 bronze badges
6
In Swift 2.0 (Xcode 7.1b), you can use
if let result = array.indexOf("Jason")
while find(array, "Jason")
is deprecated.
answered Jun 18, 2015 at 8:50
green_knightgreen_knight
1,27914 silver badges26 bronze badges
I made this function like above, but it return array of indexes
extension Array {
func indexesOf<T : Equatable>(object:T) -> [Int] {
var result: [Int] = []
for (index,obj) in enumerate(self) {
if obj as T == object {
result.append(index)
}
}
return result
}
}
Maybe it will be useful for you
Max MacLeod
26k13 gold badges104 silver badges132 bronze badges
answered Jun 11, 2014 at 10:51
Array can be bridged to an NSArray, so you can use:
array.bridgeToObjectiveC().indexOfObject("Jason")
answered Jun 8, 2014 at 10:56
Ben GottliebBen Gottlieb
85.2k22 gold badges175 silver badges171 bronze badges
2
An extension of Array can work wonders here. Here’s an implementation shared in this StackOverflow answer:
extension Array {
func find (includedElement: T -> Bool) -> Int? {
for (idx, element) in enumerate(self) {
if includedElement(element) {
return idx
}
}
return nil
}
}
answered Jun 8, 2014 at 11:02
aleclarsonaleclarson
18k14 gold badges64 silver badges89 bronze badges
1
You can add an Array Extension that does exactly what you want, i.e:
extension Array {
func indexOf<T : Equatable>(x:T) -> Int? {
for i in 0..self.count {
if self[i] as T == x {
return i
}
}
return nil
}
}
Which now lets you use .indexOf()
on all Swift arrays, e.g:
["Jason", "Charles", "David"].indexOf("Jason") //0
answered Jun 8, 2014 at 11:13
mythzmythz
141k29 gold badges243 silver badges388 bronze badges
1
While the response from Max is great, it does not let you find multiple indexes of multiple objects, ie. indexes of the subset of the array. If you need that functionality, extensions are, as always, your best friend
func indexesOfSubset<T : Equatable>(objects : [T]) -> [Int] {
// Create storage for filtered objectsand results
var unusedObjects = objects
var result : [Int] = []
// Enumerate through all objects in array
for (index, obj) in enumerate(self) {
// Enumerate again through all objects that has not been found
for x in unusedObjects {
// If we hit match, append result, remove it from usused objects
if obj as! T == x {
result.append(index)
unusedObjects = unusedObjects.filter( { $0 != x } )
break
}
}
}
// Get results
return result
}
Note* : Works on Swift 1.2, if you want compatibility with 1.1, replace as! -> as
answered Apr 14, 2015 at 14:14
Jiri TrecakJiri Trecak
5,08226 silver badges37 bronze badges
Overview
Swift provides several built-in array methods that can help you find the index of an element (when knowing its value or some of its characteristics) in a given array:
- firstIndex(of:): You can use this method to find the index of the first occurrence of a specific element in an array. It returns an optional value, so you need to unwrap it safely.
- firstIndex(where:): This one finds the index of the first element that satisfies a given condition. It takes a closure as an argument and returns an optional value.
- lastIndex(of:): This method can help you find the index of the last occurrence of a specific element in an array. It works similarly to the firstIndex(of:) method, but it searches from the end of the array.
- lastIndex(where:): This dude can find the index of the last element that satisfies a given condition. It works similarly to the firstIndex(where:) method, but it searches from the end of the array.
By flexibly using one of these four methods, you can find the index of an element whether in a simple array or a deeply nested array (like an array of dictionaries). Enough theory; let’s see some practical code examples.
Examples
Using firstIndex(of:)
This example finds the index of orange in an array of fruits:
let fruits = ["apple", "banana", "orange", "mango"]
if let index = fruits.firstIndex(of: "orange") {
print("The index of 'orange' is (index)")
} else {
print("Orange is not in the array")
}
Output:
The index of 'orange' is 2
Using firstIndex(where:)
This example demonstrates how to find the first index where an element satisfies a condition:
let numbers = [1, 2, 3, 4, 5]
if let index = numbers.firstIndex(where: { $0 > 3 }) {
print("The first index where the element is greater than 3 is (index)")
} else {
print("No element is greater than 3")
}
Output:
The first index where the element is greater than 3 is 3
Using lastIndex(of:)
The code below does one job: find the last index of a in an array that contains some letters:
let letters = ["a", "b", "c", "a", "d"]
if let index = letters.lastIndex(of: "a") {
print("The last index of 'a' is (index)")
} else {
print("a is not in the array")
}
Output:
The last index of 'a' is 3
Using lastIndex(where:)
Let’s say we have an array that stores the scores of some players (who play an unknown game). What we need to do is to find the last index where the score is less than 70:
let scores = [80, 90, 70, 60, 50]
if let index = scores.lastIndex(where: { $0 < 70 }) {
print("The last index where the score is less than 70 is (index)")
} else {
print("No score is less than 70")
}
Output:
The last index where the score is less than 70 is 4
Dealing with deeply nested arrays
In the following example, we will work with an array whose elements are dictionaries. The job is to find the index of the first dictionary that contains a specific key and value pair. We will use the firstIndex(where:) method in this case:
let books = [
["title": "The Catcher in the Rye", "author": "J.D. Salinger"],
["title": "Nineteen Eighty-Four", "author": "George Orwell"],
["title": "Animal Farm", "author": "George Orwell"],
["title": "The Hitchhiker's Guide to the Galaxy", "author": "Douglas Adams"],
]
if let index = books.firstIndex(where: { $0["author"] == "George Orwell" }) {
print("The first book by George Orwell is at index (index)")
} else {
print("No book by George Orwell is found")
}
Output:
The first book by George Orwell is at index 1