Swift
Swift programming
indexOf
list operations
Swift tutorial

How to find index of list item in Swift?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Finding an item index in Swift arrays is simple for basic cases, but robust code needs to handle optionals safely, custom matching logic, and performance under repeated lookups. Swift provides clear standard library APIs for each scenario. This guide covers practical patterns and when to use each one.

Use firstIndex(of:) for Equatable Values

If elements conform to Equatable, use firstIndex(of:) for direct value lookup.

swift
1import Foundation
2
3let fruits = ["Apple", "Banana", "Orange", "Mango"]
4
5if let idx = fruits.firstIndex(of: "Orange") {
6    print("Orange index: \(idx)")
7} else {
8    print("Orange not found")
9}
10
11if let idx = fruits.firstIndex(of: "Pear") {
12    print("Pear index: \(idx)")
13} else {
14    print("Pear not found")
15}

The returned index is optional because the value may not exist.

Use firstIndex(where:) for Custom Conditions

When matching rules are not plain equality, use a predicate closure.

swift
1import Foundation
2
3struct User {
4    let id: Int
5    let email: String
6}
7
8let users = [
9    User(id: 101, email: "[email protected]"),
10    User(id: 102, email: "[email protected]"),
11    User(id: 103, email: "[email protected]")
12]
13
14if let idx = users.firstIndex(where: { $0.email.hasSuffix("@company.com") }) {
15    print("First company user at index: \(idx)")
16}
17
18if let idx = users.firstIndex(where: { $0.id == 999 }) {
19    print("Found at index: \(idx)")
20} else {
21    print("id 999 not found")
22}

This keeps business matching logic explicit and easy to review.

Normalize Strings for User Input Searches

User-entered text often differs in case and spacing. Normalize both source and target before comparison.

swift
1import Foundation
2
3let cities = ["Toronto", "montreal", "VANCOUVER", " Calgary "]
4let target = "calgary"
5
6if let idx = cities.firstIndex(where: {
7    $0.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() == target.lowercased()
8}) {
9    print("Matched city at index: \(idx)")
10}

This pattern prevents subtle mismatch bugs in search fields.

Collect All Matching Indices When Needed

Sometimes you need every matching position, not just the first.

swift
1import Foundation
2
3let values = [1, 2, 3, 2, 2, 4]
4let allIndices = values.enumerated().compactMap { pair in
5    pair.element == 2 ? pair.offset : nil
6}
7
8print(allIndices)

This is useful in batch edits and analytics tasks.

Speed Up Repeated Lookups with an Index Map

Array index searches are linear. If you perform many lookups, precompute a dictionary from value to first index.

swift
1import Foundation
2
3let ids = [42, 7, 18, 7, 99, 42]
4var firstIndexMap: [Int: Int] = [:]
5
6for (index, value) in ids.enumerated() {
7    if firstIndexMap[value] == nil {
8        firstIndexMap[value] = index
9    }
10}
11
12print(firstIndexMap[7] as Any)
13print(firstIndexMap[99] as Any)
14print(firstIndexMap[100] as Any)

This trades memory for faster repeated reads.

Safety and Mutation Considerations

Indices are tied to array state. If elements are inserted or removed, previously stored indices may no longer point to the same item.

Good practice:

  • Recompute index after structural mutations.
  • Avoid force-unwrapping index optionals.
  • Treat indices as short-lived values.

This prevents stale-index bugs that are difficult to reproduce.

Generic Helper Pattern

A generic helper keeps lookup behavior consistent across the codebase.

swift
1func firstIndexOrMinusOne<T: Equatable>(of value: T, in array: [T]) -> Int {
2    return array.firstIndex(of: value) ?? -1
3}
4
5print(firstIndexOrMinusOne(of: "Orange", in: ["Apple", "Orange"]))
6print(firstIndexOrMinusOne(of: "Pear", in: ["Apple", "Orange"]))

Use this only if your project prefers sentinel integers over optional indices.

Common Pitfalls

  • Force-unwrapping optional indices and crashing on missing values.
  • Repeatedly scanning large arrays in hot paths instead of using lookup maps.
  • Ignoring case or whitespace normalization for user-entered text.
  • Using stale indices after array mutations.
  • Overusing custom search helpers when standard library methods are already clear.

Summary

  • Use firstIndex(of:) for direct Equatable value searches.
  • Use firstIndex(where:) for predicate-based matching.
  • Normalize strings for robust user-facing text searches.
  • Build index maps for high-frequency lookup workloads.
  • Handle optional indices safely and refresh indices after array changes.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.