Swift: دوال Swift ذات الرتبة العليا

Higher-order functions are functions that accept other functions as arguments or return functions. The Swift standard library provides powerful higher-order functions like map, filter, and reduce, letting you process collections in a declarative style.

1. What You'll Learn


2. A Real-World Data Analyst Story

(1) Pain Point: Bloated for-Loop Code for Array Processing

Bob needs to extract active users from an array, sort them by age, and format the output strings:

SWIFT
var activeUsers: [String] = []
for user in users {
    if user.isActive {
        activeUsers.append(user.name)
    }
}
activeUsers.sort()
var result: [String] = []
for name in activeUsers {
    result.append("User: \(name)")
}

Two for-loops + a temporary array + a sort. The logic is simple but the code is long and filled with "How" details instead of expressing "What."

(2) The Higher-Order Function Solution

Use functional chaining to accomplish everything in one line:

SWIFT
let result = users
    .filter { $0.isActive }
    .map { $0.name }
    .sorted()
    .map { "User: \($0)" }

Code goes from 10 lines to 4, with better readability.

(3) Benefit: The Advantages of Declarative Programming

Dimension for Loop Higher-Order Chain
Code Length 10-15 lines 3-5 lines
Readability Read loop body to understand intent Function names directly express intent
Data Flow Track intermediate variables Chain clearly shows data flow
Change Impact Rewrite loop for logic changes Add/remove steps without affecting others
Concurrency Manual management Inherently parallel-friendly (e.g. parallelMap)

3. map: Transform Each Element

map applies a transformation to each element in an array and returns a new array of the same length.

100%
graph LR
    A["[1, 2, 3, 4, 5]"] --> B["map { $0 * 2 }"]
    B --> C["[2, 4, 6, 8, 10]"]
Scenario Input Transform Output
Double values [1, 2, 3] { $0 * 2 } [2, 4, 6]
Extract property [User, User] { $0.name } ["Alice", "Bob"]
Type conversion ["1", "2"] { Int($0) } [1, 2] (type becomes [Int?])

▶ Example: Basic map Usage

SWIFT
// ============================================
// map: Apply transformation to each element
// ============================================
let numbers = [1, 2, 3, 4, 5]
// for-loop approach (old style)
var doubled: [Int] = []
for n in numbers { doubled.append(n * 2) }
// map approach (modern style)
let doubledMap = numbers.map { $0 * 2 }
print("doubledMap: \(doubledMap)")
// Extract string lengths
let words = ["Swift", "Python", "Go"]
let lengths = words.map { $0.count }
print("lengths: \(lengths)")

Output:

TEXT 📖 للعرض فقط
doubledMap: [2, 4, 6, 8, 10]
lengths: [5, 6, 2]

4. filter: Select Elements

filter keeps elements that satisfy a condition, returning a new array.

▶ Example: filter Selection Operations

SWIFT
// ============================================
// filter: Keep elements that satisfy a condition
// ============================================
let scores = [45, 82, 91, 63, 77, 55, 88]
// Filter passing scores (>= 60)
let passed = scores.filter { $0 >= 60 }
print("Passed: \(passed)")
// Filter excellent scores (>= 85)
let excellent = scores.filter { $0 >= 85 }
print("Excellent: \(excellent)")
// Chaining: filter failing scores then double them
let failedDoubled = scores
    .filter { $0 < 60 }
    .map { $0 * 2 }
print("Failed scores doubled: \(failedDoubled)")

Output:

TEXT 📖 للعرض فقط
Passed: [82, 91, 63, 77, 88]
Excellent: [91, 88]
Failed scores doubled: [90, 110]

Tip: filter returns a new array preserving the original order.


5. reduce and compactMap

(1) reduce: Combine into a Single Value

reduce combines all elements of an array into a single value.

Parameter Meaning Example
initialResult Starting value 0 for summing, "" for concatenation
nextPartialResult Accumulating closure { $0 + $1 }
100%
graph LR
    A["[1, 2, 3, 4]"] --> B["reduce(0) { $0 + $1 }"]
    B --> C["0+1=1, 1+2=3, 3+3=6, 6+4=10"]
    C --> D["10"]

▶ Example: Various reduce Use Cases

SWIFT
// ============================================
// reduce: Reduction operations
// ============================================
let numbers = [1, 2, 3, 4, 5]
// Sum
let sum = numbers.reduce(0) { $0 + $1 }
print("sum: \(sum)")
// Product
let product = numbers.reduce(1) { $0 * $1 }
print("product: \(product)")
// Concatenate strings
let words = ["Swift", "is", "awesome"]
let sentence = words.reduce("") { $0.isEmpty ? $1 : "\($0) \($1)" }
print("sentence: \(sentence)")
// Named parameters for clarity
let sumNamed = numbers.reduce(0) { total, next in total + next }
print("sumNamed: \(sumNamed)")

Output:

TEXT 📖 للعرض فقط
sum: 15
product: 120
sentence: Swift is awesome
sumNamed: 15

(2) compactMap: Filter nil Values

compactMap works like map but automatically filters out nil values.

SWIFT
// ============================================
// compactMap and flatMap
// ============================================
// compactMap: Filter nil
let strings = ["1", "two", "3", "four", "5"]
let numbers2 = strings.compactMap { Int($0) }
print("numbers: \(numbers2)")
// flatMap: Flatten nested arrays
let nested = [[1, 2], [3, 4, 5], [6]]
let flattened = nested.flatMap { $0 }
print("flattened: \(flattened)")

Output:

TEXT 📖 للعرض فقط
numbers: [1, 3, 5]
flattened: [1, 2, 3, 4, 5, 6]

6. Chaining in Practice

The most powerful use of higher-order functions is chaining — connecting multiple operations into a pipeline.

▶ Example: Complex Data Transformation Chain

SWIFT
// ============================================
// Chaining: User data analysis pipeline
// ============================================
struct User {
    let name: String
    let age: Int
    let isActive: Bool
    let scores: [Int]
}
let users = [
    User(name: "Alice", age: 28, isActive: true, scores: [85, 90, 78]),
    User(name: "Bob", age: 22, isActive: false, scores: [70, 75]),
    User(name: "Charlie", age: 35, isActive: true, scores: [95, 92, 98, 100]),
    User(name: "Diana", age: 17, isActive: true, scores: [60, 65]),
    User(name: "Eve", age: 30, isActive: false, scores: [88, 82])
]
// Chain pipeline: active users → adults → average score → sort by score → format
let report = users
    .filter { $0.isActive }
    .filter { $0.age >= 18 }
    .map { user -> (name: String, avgScore: Double) in
        let avg = Double(user.scores.reduce(0, +)) / Double(user.scores.count)
        return (user.name, avg)
    }
    .sorted { $0.avgScore > $1.avgScore }
    .map { "\($0.name): \(String(format: "%.1f", $0.avgScore))" }
print("=== Active Adult User Report ===")
report.forEach { print($0) }

Output:

TEXT 📖 للعرض فقط
=== Active Adult User Report ===
Charlie: 96.2
Alice: 84.3

7. Complete Example: Shopping Cart Price Calculator

SWIFT
// ============================================
// Complete example: Shopping cart price calculator
// Features: map + filter + reduce + compactMap combined
// ============================================
import Foundation
struct CartItem {
    let name: String
    let price: Double
    let quantity: Int
    let isDiscounted: Bool
}
let cart = [
    CartItem(name: "Laptop", price: 1299, quantity: 1, isDiscounted: false),
    CartItem(name: "Mouse", price: 29.99, quantity: 2, isDiscounted: true),
    CartItem(name: "Keyboard", price: 99.99, quantity: 1, isDiscounted: true),
    CartItem(name: "Cable", price: 9.99, quantity: 3, isDiscounted: false),
    CartItem(name: "Monitor", price: 399, quantity: 0, isDiscounted: false)
]
// 1. Filter out zero-quantity items
let validItems = cart.filter { $0.quantity > 0 }
// 2. Calculate total per item (15% off for discounted items)
let itemTotals = validItems.map { item -> (String, Double) in
    let unitPrice = item.isDiscounted ? item.price * 0.85 : item.price
    let total = unitPrice * Double(item.quantity)
    return (item.name, total)
}
// 3. Calculate grand total
let grandTotal = itemTotals.reduce(0) { $0 + $1.1 }
// 4. Format output
print("=== Shopping Cart ===")
itemTotals.forEach { print("  \($0): $\(String(format: "%.2f", $1))") }
print("  ----------")
print("  Total: $\(String(format: "%.2f", grandTotal))")

Output:

TEXT 📖 للعرض فقط
=== Shopping Cart ===
 Laptop: $1299.00
 Mouse: $50.98
 Keyboard: $84.99
 Cable: $29.97
  ----------
  Total: $1464.94

❓ FAQ

س What's the difference between map and forEach?
ج map returns a new array; forEach only iterates without returning. Use map when you want to transform data into a new array. Use forEach only for side effects (like printing).
س What's the difference between flatMap and compactMap?
ج In Swift 4.1+, flatMap flattens nested collections (e.g. [[1,2], [3]][1,2,3]), while compactMap filters out nil values (e.g. [1, nil, 3][1, 3]). Each has its own role.
س Does chaining hurt performance?
ج Each call creates a new array, so there are intermediate allocation costs. For small to medium data (a few thousand elements or fewer), the impact is negligible. For large datasets, consider using lazy for deferred evaluation: array.lazy.filter { ... }.map { ... }.
س Can reduce handle empty arrays?
ج Yes. reduce simply returns the initial value. For example, [].reduce(0, +) returns 0. However, if the initial value isn't appropriate for empty arrays (e.g. finding a maximum), check isEmpty first.
س Can higher-order functions replace all for loops?
ج Most of the time, yes. But for loops are better for certain cases: when you need to break in the middle, need indices for complex operations, or need to access adjacent elements. Use higher-order functions for: transforming, filtering, reducing, flattening.

📖 Summary


📝 Exercises

  1. Basic: Given the integer array [10, 20, 30, 40, 50], first use map to divide each element by 2, then use filter to keep elements greater than 15.
  2. Intermediate: Given the string array ["apple", "banana", "kiwi", "strawberry", "fig"], use chaining to filter strings with length >= 5, convert to uppercase, and sort alphabetically.
  3. Challenge: Given an array of Transaction structs (properties: amount: Double, category: String, date: Date), use reduce(into:) to group and sum amounts by category. Then output the total for each category.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%