Swift map() Tutorial (With Examples)

If you’ve ever written a for loop just to build a new array from an existing one, there’s a better way — and once you see it, you’ll use it all the time.
Written by

Chris C

Updated on

Apr 06 2026

Table of contents

    The Swift map() function is one of the most useful tools in the Swift language. It lets you transform every element in a collection — an array, a set, even an optional — and get a new collection back with your changes applied. No for loops, no manually appending to a new array, no extra boilerplate. Just a clean one-liner that says exactly what it does.

    Imagine you have an array of product prices and you need to apply a 10% discount to every one. Or you have a list of usernames and want to display them all in uppercase. Or you’re pulling raw data from an API and need to convert each item into a model object. All of these are exactly the kind of problem map() was built for.

    In this article, you’ll learn what Swift map() does, how the syntax works, the most useful variations, and how to use it in real iOS code. By the end, you’ll have a solid handle on one of Swift’s most powerful higher-order functions.

    The Basic Syntax

    Here’s the simplest possible example of Swift’s map() function. Drop this into a Swift Playground and run it:

    let numbers = [1, 2, 3, 4, 5]
    
    let doubled = numbers.map { $0 * 2 }
    
    print(doubled)  // [2, 4, 6, 8, 10]

    That’s it. Three lines, and you’ve transformed an entire array. Let’s walk through each part:

    LineWhat it does
    let numbers = [1, 2, 3, 4, 5]This is the original array — the one you want to transform. You’re not going to change this array directly.
    numbers.map { }This calls the map() function on your array. The curly braces contain a closure — a small block of code that runs once for every element in the array.
    $0This is shorthand for “the current element.” As map loops through your array, each element gets passed in here. So when map is processing the number 3, $0 is 3.
    $0 * 2This is the transformation. You’re saying: take the current element and multiply it by 2. Map collects all these results and builds a new array.
    let doubled = ...The result of map is stored in doubled. The original numbers array is not modified. Map always returns a brand new array.

    Breaking It Down

    Now that you’ve seen it in action, let’s look at the parts that matter and clear up the things that trip people up.

    map() always returns a new array

    This is the most important thing to internalize. When you call map() on an array, it does not change the original. It reads through every element, applies your closure to each one, and returns a brand new array with the results. The original array is untouched.

    The closure is required

    The closure inside the curly braces is not optional. It’s how you tell map what transformation to apply. If you don’t provide one, the code won’t compile.

    The result can be a different type

    You don’t have to return the same type you started with. If you start with an array of integers, you could use map to return an array of strings. This is one of map’s most powerful features. You’ll see this in practice a lot when working with data models — for example, converting an array of raw API strings into an array of your own struct type.

    You can write the closure in multiple ways

    Swift gives you several ways to write the same closure. The shorthand { $0 * 2 } is the most compact, but you can also write it out more explicitly if it helps you understand what’s happening. Both of these do the exact same thing:

    let numbers = [1, 2, 3, 4]
    
    // Shorthand — most common in real code
    let result1 = numbers.map { $0 * 2 }
    
    // Named parameter — easier to read when learning
    let result2 = numbers.map { number in number * 2 }
    
    // Explicit long form — shows exactly what map expects
    let result3 = numbers.map({ (number: Int) -> Int in
        return number * 2
    })

    When you’re starting out, the named parameter form { number in number * 2 } is often easier to read. Once you get comfortable, the shorthand { $0 * 2 } is what you’ll see in most real-world Swift code.

    Common gotcha: Beginners sometimes expect map() to modify the original array in place. It doesn’t. If you print numbers after calling map, it will still have the original values. Always capture the result in a new variable.

    Variations and Syntax Patterns

    Map is not just for arrays of numbers. Here are the most important variations you’ll encounter as a beginner — each one builds on the same core idea but applies it in a different context.

    map with Strings Transform each string in an array
    let names = ["alice", "bob", "charlie"]
    
    let uppercased = names.map { $0.uppercased() }
    
    print(uppercased)  // ["ALICE", "BOB", "CHARLIE"]
    String arrays are one of the most common uses of map. Here you call a method on each element instead of a math operation, but map works the same way. You can call any String method inside the closure: lowercased(), capitalized, count, or anything else.
    map changing the type Convert elements from one type to another
    let prices = [10, 25, 50]
    
    // Int array → String array
    let labels = prices.map { "$\($0)" }
    
    print(labels)  // ["$10", "$25", "$50"]
    Map can return a completely different type from what you started with. Here you start with an array of Int values and end up with an array of String values. Swift infers the type of the new array automatically based on what your closure returns. This is incredibly useful when formatting data for display.
    map with a named closure Use a separate function as the transformation
    func addTax(to price: Double) -> Double {
        return price * 1.13
    }
    
    let prices: [Double] = [9.99, 24.99, 49.99]
    let withTax = prices.map(addTax)
    
    print(withTax)  // [11.2887, 28.2387, 56.4887]
    You can pass a named function directly to map instead of writing an inline closure. This is useful when the transformation logic is complex enough to deserve its own function, or when you want to reuse the same transformation in multiple places. Swift will call your function once for each element.
    compactMap Transform and remove nil values in one step
    let strings = ["1", "two", "3", "four", "5"]
    
    // map would give you [Optional(1), nil, Optional(3), nil, Optional(5)]
    // compactMap filters out the nils automatically
    let numbers = strings.compactMap { Int($0) }
    
    print(numbers)  // [1, 3, 5]
    compactMap is like map, but it automatically removes any nil results. When your transformation might fail for some elements — like trying to convert a string to an integer — compactMap gives you back only the successful results. The resulting array contains no optionals, which makes it much easier to work with.
    flatMap Transform and flatten nested arrays into one
    let groups = [[1, 2], [3, 4], [5]]
    
    // map would give: [[1, 2], [3, 4], [5]] — still nested
    let flat = groups.flatMap { $0 }
    
    print(flat)  // [1, 2, 3, 4, 5]
    flatMap is for situations where your transformation returns an array for each element, but you want the results merged into a single flat array. A common use case: you have a list of categories, each with its own array of items, and you want one combined list of all items.
    map on Optional Transform a value that might be nil
    let username: String? = "alice"
    
    let greeting = username.map { "Hello, \($0)!" }
    
    print(greeting)  // Optional("Hello, alice!")
    
    let empty: String? = nil
    let noGreeting = empty.map { "Hello, \($0)!" }
    
    print(noGreeting)  // nil
    Optionals in Swift also have a map() method. If the optional has a value, map applies the transformation and wraps the result in a new optional. If the optional is nil, map skips the transformation entirely and returns nil. This is a clean way to transform optional values without needing an explicit if let check.

    How Swift map() Appears in Real iOS Code

    So far you’ve seen map() with simple arrays of numbers and strings. Now let’s look at how it shows up in actual iOS app code — because this is where it really earns its place.

    One of the most common patterns in iOS development is fetching data from an API and converting the raw response into your own model objects. Here’s a simplified version of that pattern using map():

    import Foundation
    
    // Your model struct
    struct Product {
        let name: String
        let displayPrice: String
    }
    
    // Raw data you might receive from an API
    let rawData: [[String: Any]] = [
        ["name": "Hoodie", "price": 49],
        ["name": "T-Shirt", "price": 25],
        ["name": "Hat", "price": 20]
    ]
    
    // Use map to convert each dictionary into a Product
    let products = rawData.compactMap { dict -> Product? in
        guard
            let name = dict["name"] as? String,
            let price = dict["price"] as? Int
        else { return nil }
    
        return Product(name: name, displayPrice: "$\(price)")
    }
    
    // Now you have a clean [Product] array to work with
    for product in products {
        print("\(product.name): \(product.displayPrice)")
    }
    // Hoodie: $49
    // T-Shirt: $25
    // Hat: $20

    Here’s what makes this example realistic and worth understanding:

    compactMap is used instead of map because the conversion might fail. If a dictionary entry is missing its “name” or “price” key, guard catches that and returns nil. compactMap then silently removes those failed conversions from the result. This keeps your final array clean.

    The closure returns a custom type (Product) instead of a primitive. This is the pattern you’ll use when decoding API data into model objects. In a real app, this raw dictionary would come from JSON parsing, but the map/compactMap pattern is the same.

    The price formatting happens inside the closure. Instead of converting prices separately in a second step, you handle it right inside the transformation. This is one of the reasons map leads to cleaner, more readable code.

    Here’s another pattern you’ll see constantly in SwiftUI apps — using map to prepare display data:

    import SwiftUI
    
    struct Task {
        let title: String
        let isComplete: Bool
    }
    
    let tasks = [
        Task(title: "Design splash screen", isComplete: true),
        Task(title: "Write unit tests", isComplete: false),
        Task(title: "Submit to App Store", isComplete: false)
    ]
    
    // Get just the titles as a [String] array
    let titles = tasks.map { $0.title }
    
    // Get a count of completed tasks
    let completionStatus = tasks.map { $0.isComplete }
    let completedCount = completionStatus.filter { $0 }.count
    
    print(titles)          // ["Design splash screen", "Write unit tests", "Submit to App Store"]
    print(completedCount)  // 1

    Extracting a single property from every element of an array is something you’ll do constantly when working with SwiftUI lists and data models. Map is the cleanest way to do it.

    Common Mistakes to Avoid

    Here are the mistakes that show up again and again when beginners first start using Swift’s map() function.

    Mistake 1: Expecting map() to change the original array

    This is the most common one. You call map(), but then you print the original array and wonder why nothing changed. Map never modifies the original. It always creates and returns a new array. If you don’t capture the result in a variable, the transformation is simply discarded.

    var numbers = [1, 2, 3]
    
    // This does nothing useful — the result is thrown away
    numbers.map { $0 * 2 }
    
    // This is correct — capture the result
    let doubled = numbers.map { $0 * 2 }
    Tip: Xcode will actually warn you with a “result of call to map is unused” message. If you see that warning, it’s a sign you forgot to capture the result.

    Mistake 2: Using map when compactMap is what you need

    If your transformation can return nil for some elements, using plain map() will give you an array of optionals — which you then have to unwrap everywhere. compactMap handles both the transformation and the nil filtering in one pass, giving you a clean non-optional array.

    let strings = ["1", "abc", "3"]
    
    // map gives you [Optional(1), nil, Optional(3)] — messy
    let withNils = strings.map { Int($0) }
    
    // compactMap gives you [1, 3] — clean
    let clean = strings.compactMap { Int($0) }

    Mistake 3: Writing a for loop when map would be cleaner

    This isn’t wrong, but it’s worth recognizing. If you find yourself writing a for loop that just builds a new array from an existing one, that’s almost always a map waiting to be written. The map version is shorter, has no mutable state, and communicates your intent more clearly.

    let names = ["alice", "bob"]
    
    // The for loop version — more code, less clear
    var result: [String] = []
    for name in names {
        result.append(name.uppercased())
    }
    
    // The map version — shorter and more expressive
    let upper = names.map { $0.uppercased() }

    Mistake 4: Confusing map with filter

    Map transforms each element and always returns an array of the same count. Filter removes elements and returns a smaller array. They’re often used together, but they do very different things. If you want to both transform and narrow down a list, you’d use filter first, then map (or combine them with chaining).

    Remember: Map changes what each element is. Filter changes which elements are included. They’re designed to work together, not as substitutes for each other.

    Quick Reference

    Here’s a summary of the Swift map variations covered in this article, formatted as a quick cheat sheet you can come back to:

    SyntaxWhat It Does
    array.map { $0 * 2 }Transforms every element, returns a new array of the same size
    array.map { $0.uppercased() }Calls a method on each element and collects results
    array.map { “Label: \($0)” }Converts elements to a different type (here, Int to String)
    array.map { item in item.property }Extracts a property from each element using named parameter syntax
    array.compactMap { Int($0) }Transforms and removes nil results — great for failable conversions
    array.flatMap { $0 }Transforms and flattens nested arrays into a single array
    optional.map { transform }Transforms an optional value if it exists, returns nil if not
    array.map(functionName)Passes a named function as the transformation instead of an inline closure

    When To Use Swift map()

    • 🛍️

      A shopping or e-commerce app

      You fetch a list of products from an API and need to convert raw JSON dictionaries into your own Product model objects. You also need to format prices for display and apply discounts to a cart total. Map is the right tool for all three of these — it’s clean, it handles the whole array in one pass, and it leaves your original data untouched.

    • A to-do or task management app

      You have an array of Task objects and need to extract just the titles for a SwiftUI List, or pull out a boolean array of completion states to calculate progress. Map makes both of these one-liners. You might also use compactMap to get only tasks that have a due date, skipping the ones that don’t.

    • 📊

      A fitness tracker or data-heavy app

      You’re displaying workout history and need to convert raw step counts into formatted strings like “10,423 steps”. Or you need to scale a set of values to fit a chart. Map is ideal here — it transforms every data point consistently, with no loops and no mutable variables.

    Rule of thumb: Any time you would write a for loop to build a new array from an existing one, ask yourself if map could replace it. If the answer is yes, it almost always should. The map version is shorter, clearer about its intent, and produces safer code because there’s no mutable intermediate array.

    Using AI to Go Deeper with Swift map()

    AI coding tools are part of how developers work today. Knowing the right prompts to use — especially ones that make you understand the output rather than just copy it — is a skill in itself.

    Deepen Your Understanding Use AI as a tutor — no code generation required
    Explain Swift’s map() function to me like I’m a beginner. Use a real-world analogy first, then show me the simplest possible code example and walk through it line by line.
    I think I understand map() vs compactMap() vs flatMap() in Swift but I’m not 100% sure when to use each one. Can you quiz me? Ask me one scenario at a time and tell me which I should use and why.
    Build a Practice Example Generate commented, learning-focused code you can study line by line
    Write a short Swift example that uses map() to convert an array of custom structs into display-ready strings for a SwiftUI list. Add a comment on every line explaining what it does and why — write the comments for a beginner seeing this for the first time.
    Give me 3 different Swift examples using map(), compactMap(), and flatMap() respectively, each one with a realistic iOS context. Add inline comments throughout so I can follow the logic without needing prior experience with higher-order functions.
    Audit Your Own Code Use AI to review code you’ve written — you stay in the driver’s seat
    Here’s some Swift code I wrote: [paste your code]. Can you tell me if there are any places where I should be using map(), compactMap(), or flatMap() instead of what I have? Explain why for each one before suggesting any changes.
    Review this Swift code for how I’m using map(): [paste your code]. Am I using it correctly? Are there any improvements I could make to make it more idiomatic or readable? Please explain the reasoning before showing me the change.
    Important: Whether you use AI to generate an example or to review your code, always make sure you can explain every line before you move on. If you can’t explain what the closure does and why, the AI should be explaining it to you — not writing your next piece of code.

    Summary

    Here’s a quick recap of what you learned about Swift map():

    • map() transforms every element in a collection and returns a new array of the same size
    • It never modifies the original array — always capture the result in a new variable
    • The closure receives each element as $0 by default, or you can name it with item in syntax
    • Map can return a different type than it started with — this is one of its most useful traits
    • compactMap removes nil results, flatMap flattens nested arrays, and Optional.map handles optionals safely
    • In iOS apps, map is commonly used to convert API data into model objects and prepare display strings
    • Any time you’re writing a for loop that builds a new array, map is worth considering instead

    The best way to get comfortable with map() is to try replacing your next for loop with it. Even if the result feels unfamiliar at first, the pattern will click quickly once you’ve used it a few times in real code.

    Once you’re confident with map(), a great next step is to explore filter() and reduce() — the other two essential higher-order functions in Swift. Together, the three of them cover most of the data transformation work you’ll do in any iOS app.



    Get started for free

    Join over 2,000+ students actively learning with CodeWithChris