Hello, Swift developers! Today, we’re exploring another powerful higher-order function: filter
. If you’ve ever needed to separate the wheat from the chaff in your collections, filter
is about to become your new best friend.
What is Filter?
The filter
method creates a new collection containing only the elements that satisfy a given condition. It’s like having a bouncer for your data party!
Basic Usage
Let’s start with a simple example:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers)
// Output: [2, 4, 6, 8, 10]
Here, we’ve filtered out all the odd numbers, leaving us with only the evens.
Filtering Complex Types
Filter isn’t just for simple types. Let’s use it with a custom struct:
struct Student {
let name: String
let grade: Int
}
let students = [
Student(name: "Alice", grade: 85),
Student(name: "Bob", grade: 70),
Student(name: "Charlie", grade: 90),
Student(name: "David", grade: 65)
]
let highAchievers = students.filter { $0.grade >= 80 }
highAchievers.forEach {
print("\($0.name) is a high achiever!")
}
// Output:
// Alice is a high achiever!
// Charlie is a high achiever!
Chaining Filter Calls
You can chain multiple filter
calls for more complex filtering:
let multipleOfThreeAndEven = numbers.filter { $0 % 3 == 0 }
.filter { $0 % 2 == 0 }
print(multipleOfThreeAndEven)
// Output: [6]
Filter with Optionals
Swift’s filter
works great with optionals too:
let optionalNumbers: [Int?] = [1, nil, 3, nil, 5]
let nonNilNumbers = optionalNumbers.compactMap { $0 }
print(nonNilNumbers)
// Output: [1, 3, 5]
// Alternatively, you can use filter before compactMap
let filteredNumbers = optionalNumbers.filter { $0 != nil }
.compactMap { $0 }
print(filteredNumbers)
// Output: [1, 3, 5]
Filter with Dictionaries
Don’t forget, filter
works on dictionaries too:
let grades = ["Alice": 85, "Bob": 70, "Charlie": 90, "David": 65]
let highGrades = grades.filter { $0.value >= 80 }
print(highGrades)
// Output: ["Alice": 85, "Charlie": 90]
Filter with Strings
Strings are collections too! You can filter characters in a string:
let mixedString = "ab12cd34ef"
let onlyLetters = mixedString.filter { $0.isLetter }
print(onlyLetters)
// Output: "abcdef"
Filtering Nested Collections
When dealing with nested collections, you might want to use filter
in combination with flatMap
:
let nestedArrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let evenInNestedArrays = nestedArrays.flatMap { $0 }
.filter { $0 % 2 == 0 }
print(evenInNestedArrays)
// Output: [2, 4, 6, 8]
Filter in the Real World
Let’s look at a more practical example. Say you’re building a task management app:
struct Task {
let id: Int
let title: String
let isCompleted: Bool
}
let tasks = [
Task(id: 1, title: "Buy groceries", isCompleted: false),
Task(id: 2, title: "Finish report", isCompleted: true),
Task(id: 3, title: "Call mom", isCompleted: false),
Task(id: 4, title: "Gym workout", isCompleted: true)
]
let incompleteTasks = tasks.filter { !$0.isCompleted }
incompleteTasks.forEach { task in
print("ToDo: \(task.title)")
}
// Output:
// ToDo: Buy groceries
// ToDo: Call mom
let completedTasks = tasks.filter { $0.isCompleted }
print("You've completed \(completedTasks.count) tasks!")
// Output: You've completed 2 tasks!
Performance Considerations
While filter
is incredibly useful, be mindful of performance when working with large collections. If you only need to find the first matching element, consider using first(where:)
instead:
let firstEvenNumber = numbers.first { $0 % 2 == 0 }
print(firstEvenNumber ?? "No even numbers found")
// Output: Optional(2)
Wrapping Up
As you can see, filter
is an incredibly powerful tool in your Swift arsenal. It allows you to sift through collections with precision, whether you’re working with simple types, complex objects, or nested structures.
Remember, like map
, filter
doesn’t modify the original collection – it always returns a new one. This makes it perfect for maintaining the integrity of your original data while extracting exactly what you need.
So the next time you find yourself writing a for-loop with a bunch of if-statements to extract certain elements from a collection, ask yourself: “Could I use filter
here?” Chances are, you can – and your code will be all the cleaner and more expressive for it!