Swift contains and allSatisfy: Check Collection Values
Swift collections often need simple yes-or-no checks: does this collection include a value, and do all elements match a rule? That is exactly what contains and allSatisfy are for. In this article, you will learn what each method does, how their closure-based forms work, when to use one instead of the other, and how to avoid common mistakes when checking arrays, sets, and other sequences.
Quick answer: Use contains when you want to know whether at least one element matches a value or condition. Use allSatisfy when you want to know whether every element in the collection matches a condition.
Difficulty: Beginner
Helpful to know first: You will understand this better if you know basic Swift syntax, how arrays store values, and how simple closures return Bool values.
1. What Is contains and allSatisfy?
contains and allSatisfy are standard library methods available on Swift sequences such as arrays, sets, ranges, and many other collection-like types.
- contains answers: “Is there at least one matching element?”
- allSatisfy answers: “Do all elements match this rule?”
- Both methods return a Bool.
- contains can check for a specific value or use a closure to test a condition.
- allSatisfy always uses a closure-based condition.
These methods solve a very common problem: checking a collection without writing a full loop yourself. Instead of manually iterating and tracking a flag variable, you can express your intent directly.
These two methods are also naturally compared because they sound similar but answer different questions. contains looks for any match. allSatisfy checks whether every element passes.
2. Why contains and allSatisfy Matters
These methods make code easier to read because they describe the exact question you are asking.
For example, in real projects you may need to:
- Check whether a shopping cart contains a specific product ID.
- Check whether any username in a list is empty.
- Verify that all form fields are valid before submitting.
- Confirm that all downloaded values are positive.
- See whether a set of permissions contains an expected role.
Without these methods, you would often write a loop, compare each element, and stop manually when the answer is known. That works, but it is more verbose and easier to get wrong. Using contains or allSatisfy makes the code shorter and clearer.
Both methods can stop early. For example, contains can return as soon as it finds a match, and allSatisfy can return as soon as it finds an element that fails the rule.
3. Basic Syntax or Core Idea
Using contains with a value
If the collection elements are comparable for equality, you can ask whether a collection contains a specific value.
let numbers = [10, 20, 30]
let hasTwenty = numbers.contains(20)
print(hasTwenty) // trueThis form is simple: Swift checks whether any element equals 20.
Using contains with a closure
Use the closure form when you want to match a condition instead of one exact value.
let numbers = [10, 20, 30]
let hasLargeValue = numbers.contains { number in
number > 25
}
print(hasLargeValue) // trueThe closure returns true for a matching element. If any element returns true, then contains returns true.
Using allSatisfy with a closure
allSatisfy checks whether every element passes the condition.
let scores = [80, 92, 88]
let allPassed = scores.allSatisfy { score in
score >= 50
}
print(allPassed) // trueIf even one score fails the condition, allSatisfy returns false.
The core difference
Think of them like this:
- contains = at least one match
- allSatisfy = every element matches
4. Step-by-Step Examples
Example 1: Check for a specific string
This example uses contains to check whether a list of names includes a specific value.
let names = ["Ava", "Noah", "Mia"]
let hasMia = names.contains("Mia")
print(hasMia) // trueThis is the best form when you know the exact value you want to find.
Example 2: Check whether any number is even
Here, an exact value is not enough. We want to test a rule, so the closure form of contains is the right choice.
let values = [3, 7, 10, 13]
let hasEven = values.contains { value in
value % 2 == 0
}
print(hasEven) // trueThe method returns true because 10 matches the condition.
Example 3: Check whether all strings are non-empty
allSatisfy is useful when every element must meet a rule.
let usernames = ["alice", "bob", "charlie"]
let allHaveText = usernames.allSatisfy { !$0.isEmpty }
print(allHaveText) // trueThis reads cleanly: all usernames satisfy the rule of being non-empty.
Example 4: Check object properties with contains
These methods are especially useful with custom types. In this example, we check whether any task is overdue.
struct Task {
let title: String
let isOverdue: Bool
}
let tasks = [
Task(title: "Send invoice", isOverdue: false),
Task(title: "Reply to email", isOverdue: true)
]
let hasOverdueTask = tasks.contains { task in
task.isOverdue
}
print(hasOverdueTask) // trueThis approach avoids writing a manual loop and clearly expresses the intent.
5. Practical Use Cases
- Checking whether a cart contains a product before allowing checkout changes.
- Verifying that all password rules are met for a list of imported accounts.
- Testing whether any log message contains an error keyword.
- Confirming that all API response items have valid IDs.
- Checking whether a permissions set contains a required role.
- Verifying that all uploaded filenames have an allowed extension.
- Detecting whether any score falls below a minimum threshold.
6. Common Mistakes
Mistake 1: Using contains when you really mean allSatisfy
A common beginner mistake is choosing contains for a rule that every element must satisfy.
Problem: This code only checks whether at least one number is positive, not whether all numbers are positive. The result can be true even when some elements fail the rule.
let numbers = [5, -2, 8]
let allPositive = numbers.contains { $0 > 0 }
print(allPositive) // true, but misleadingFix: Use allSatisfy when the condition must hold for every element.
let numbers = [5, -2, 8]
let allPositive = numbers.allSatisfy { $0 > 0 }
print(allPositive) // falseThe corrected version works because allSatisfy checks every element instead of stopping at the first success.
Mistake 2: Trying to pass a value to allSatisfy
allSatisfy does not have the same direct-value form as contains. It expects a closure that returns Bool.
Problem: This code is not valid Swift because allSatisfy requires a predicate closure, not a single value to compare against.
let statuses = ["ready", "ready", "ready"]
let allReady = statuses.allSatisfy("ready")Fix: Provide a closure that compares each element with the expected value.
let statuses = ["ready", "ready", "ready"]
let allReady = statuses.allSatisfy { $0 == "ready" }
print(allReady) // trueThe corrected version works because the closure checks each element one at a time.
Mistake 3: Forgetting that empty collections affect allSatisfy
Many developers expect allSatisfy to return false for an empty collection, but that is not how it works.
Problem: An empty collection has no elements that fail the condition, so allSatisfy returns true. This can surprise you if you also need at least one element.
let scores: [Int] = []
let allPassed = scores.allSatisfy { $0 >= 50 }
print(allPassed) // trueFix: If your rule requires a non-empty collection, combine allSatisfy with an emptiness check.
let scores: [Int] = []
let allPassed = !scores.isEmpty && scores.allSatisfy { $0 >= 50 }
print(allPassed) // falseThe corrected version works because it checks both requirements: there must be elements, and they must all pass.
7. Best Practices
Practice 1: Use the simplest form of contains when checking one exact value
If you only need to find one exact value, prefer the direct-value form of contains. It is more readable than writing a closure for the same comparison.
// Less preferred
let roles = ["admin", "editor", "viewer"]
let hasAdmin = roles.contains { $0 == "admin" }
// Preferred
let betterHasAdmin = roles.contains("admin")The preferred version is easier to scan because it directly communicates the search value.
Practice 2: Choose method names that reflect the question you are asking
Store the result in a variable whose name makes the logic obvious. This becomes especially useful in conditions and validation code.
let emails = ["[email protected]", "[email protected]"]
let allEmailsValid = emails.allSatisfy { $0.contains("@") }
if allEmailsValid {
print("Ready to submit")
}A descriptive Boolean name helps the condition read like plain English.
Practice 3: Keep closure conditions focused and easy to read
If the condition is too complex, move the logic into a helper property or function. This keeps collection checks expressive instead of cluttered.
struct User {
let name: String
let age: Int
var isAdult: Bool {
age >= 18
}
}
let users = [
User(name: "Anna", age: 21),
User(name: "Ben", age: 19)
]
let allAdults = users.allSatisfy { $0.isAdult }This version is cleaner than putting a long rule directly inside the closure.
8. Limitations and Edge Cases
- contains with a direct value requires elements that can be compared for equality. For custom types, you may need to conform to Equatable, or use the closure form.
- allSatisfy returns true for empty collections. This is correct behavior, but it may not match business rules that require at least one element.
- Both methods return only a Boolean. If you need the matching element itself, methods such as first(where:) may be more appropriate.
- If your closure has side effects, the code becomes harder to reason about. Prefer pure checks that simply return true or false.
- On unordered collections such as sets, you should not depend on any specific checking order, even though the Boolean result is correct.
- If a collection is very large, these methods still need to inspect elements until the answer is known. They are concise, but not magically free.
9. Practical Mini Project
This mini project validates a list of orders. We want to know whether any order is urgent and whether all orders are ready to ship.
struct Order {
let id: Int
let isUrgent: Bool
let isPacked: Bool
}
let orders = [
Order(id: 101, isUrgent: false, isPacked: true),
Order(id: 102, isUrgent: true, isPacked: true),
Order(id: 103, isUrgent: false, isPacked: true)
]
let hasUrgentOrder = orders.contains { $0.isUrgent }
let allOrdersPacked = orders.allSatisfy { $0.isPacked }
print("Urgent order present:", hasUrgentOrder)
print("All orders packed:", allOrdersPacked)This example shows both methods working together in a realistic validation scenario. contains answers whether at least one urgent order exists, while allSatisfy confirms whether every order is packed.
10. Key Points
- contains checks whether at least one element matches.
- allSatisfy checks whether every element matches.
- contains can compare a direct value or use a closure.
- allSatisfy uses a closure that returns Bool.
- Use contains for “any?” questions and allSatisfy for “all?” questions.
- Be careful with empty collections because allSatisfy returns true for them.
11. Practice Exercise
Create a Swift program that works with an array of temperatures.
- Store several Int temperature values in an array.
- Use contains to check whether any temperature is below zero.
- Use allSatisfy to check whether all temperatures are below 40.
- Print both results.
Expected output: Two printed Boolean results: one for whether any temperature is freezing, and one for whether all temperatures are under the limit.
Hint: Use closure expressions such as { $0 < 0 } and { $0 < 40 }.
let temperatures = [12, -3, 18, 25]
let hasFreezingTemperature = temperatures.contains { $0 < 0 }
let allBelowLimit = temperatures.allSatisfy { $0 < 40 }
print("Any below zero:", hasFreezingTemperature)
print("All below 40:", allBelowLimit)12. Final Summary
contains and allSatisfy are small methods, but they solve very common collection-checking problems in a clear and expressive way. Use contains when you want to know whether any matching element exists, and use allSatisfy when every element must follow the same rule.
You also saw that the direct-value form of contains is ideal for exact matches, while closure-based checks are better for custom logic. Just be careful with empty collections and choose the method that matches your real question: “any?” or “all?” A good next step is to learn related collection methods such as first(where:), filter, and map so you can do more than just Boolean checks.