Overview
Swift's filter method lets you create a new array containing only the elements that match a condition. Instead of writing a loop, checking each item, and appending matches by hand, you describe the rule and let Swift do the scanning.
Think of a recipe app showing only vegetarian recipes, a task app showing only incomplete tasks, or a score list showing only high scores. Those are all filtering problems.
Basic Syntax
The closure you pass to filter receives each element and returns true when Swift should keep that element.
let filteredArray = array.filter { item in
return condition
}For each item, the closure answers one question: should this item stay in the new array?
Filtering Numbers
Here is a simple example that keeps only numbers greater than five:
let numbers = [2, 8, 3, 11, 4, 9]
let bigNumbers = numbers.filter { number in
number > 5
}
print(bigNumbers)The result is [8, 11, 9]. The original numbers array does not change.
Using Shorthand Syntax
Swift lets you shorten simple filter closures with $0, which means the current element.
let numbers = [2, 8, 3, 11, 4, 9]
let bigNumbers = numbers.filter {
$0 > 5
}This version does the same thing as the named number in version. Shorthand is great for short conditions, but named parameters can be clearer when the logic grows.
Filtering Strings
Filter works with any array type, including strings.
let names = ["Alex", "Maya", "Chris", "Ava"]
let namesStartingWithA = names.filter {
$0.hasPrefix("A")
}
print(namesStartingWithA)This keeps "Alex" and "Ava" because they pass the condition.
Removing Empty Strings
A common filter use case is cleaning up user input.
let userInputs = ["Alice", "", "Bob", "", "Carol"]
let nonEmptyInputs = userInputs.filter {
!$0.isEmpty
}
print(nonEmptyInputs)Remember the mental model: return true for the values you want to keep. This example keeps strings that are not empty.
Filtering Custom Structs
In app code, you often filter arrays of your own models.
struct Task {
let title: String
let isComplete: Bool
let priority: Int
}
let tasks = [
Task(title: "Study filter", isComplete: false, priority: 3),
Task(title: "Submit app", isComplete: true, priority: 5),
Task(title: "Fix bug", isComplete: false, priority: 5)
]
let pendingTasks = tasks.filter { task in
!task.isComplete
}
let highPriorityPendingTasks = tasks.filter { task in
!task.isComplete && task.priority >= 5
}Once the closure has a named parameter like task, you can access properties with normal dot syntax.
Using Filter in SwiftUI Data
In SwiftUI, filtered arrays are often expressed as computed properties derived from one source array.
struct TaskListViewModel {
var tasks: [Task]
var pendingTasks: [Task] {
tasks.filter { !$0.isComplete }
}
var urgentTasks: [Task] {
tasks.filter { !$0.isComplete && $0.priority >= 5 }
}
}This keeps one source of truth and recalculates the filtered views from that source.
Filter Does Not Modify the Original Array
Filter returns a new array. It does not remove items from the original one.
var items = [1, 2, 3, 4, 5]
let oddItems = items.filter {
$0 % 2 != 0
}
print(items)
print(oddItems)If you want to actually remove items from a mutable array, use removeAll(where:).
var items = [1, 2, 3, 4, 5]
items.removeAll {
$0 % 2 == 0
}
print(items)Filter vs CompactMap
If your goal is to remove nil values from an array of optionals, use compactMap instead.
let maybeNumbers: [Int?] = [1, nil, 3, nil, 5]
let numbers = maybeNumbers.compactMap {
$0
}
print(numbers)filter keeps or removes existing elements. compactMap can unwrap optionals and remove the nils in one step.
Common Mistakes
Forgetting to store the result
Calling filter without using its return value does not change anything.
numbers.filter { $0 > 5 }
let bigNumbers = numbers.filter { $0 > 5 }Thinking in terms of what to remove
Filter keeps elements where the closure returns true. Write the condition for what should remain.
Using filter for complex transformations
If you need to change each value, use map. If you need to transform values and remove nil results, use compactMap.
Quick Reference
| Syntax | What It Does |
|---|---|
array.filter { $0 > value } | Keeps elements greater than a value |
array.filter { $0.hasPrefix("A") } | Keeps strings that start with a prefix |
array.filter { !$0.isEmpty } | Removes empty strings |
array.filter { $0.isComplete } | Keeps items where a Boolean property is true |
array.filter { item in item.a && item.b } | Combines multiple conditions |
array.compactMap { $0 } | Removes nil values from an optional array |
Summary
filterreturns a new array containing only elements that pass a condition.- The closure returns
trueto keep an element andfalseto drop it. - The original array is not modified.
$0is shorthand for the current element.- Filter works with arrays of numbers, strings, structs, classes, and any other Swift type.
- Use
removeAll(where:)when you want to mutate an existing array. - Use
compactMapwhen you want to remove nil values from an optional array.
The best way to get comfortable with filter is to find a loop that builds a smaller array and rewrite it as a filter call. After a few tries, the closure syntax starts to feel natural.