I'm aware of Swift's higher-order functions like Map, Filter, Reduce and FlatMap, but I'm not aware of any like 'All' or 'Any' which return a boolean that short-circuit on a positive test while enumerating the results.
For instance, consider you having a collection of 10,000 objects, each with a property called isFulfilled
and you want to see if any in that collection have isFulfilled
set to false. In C#, you could use myObjects.Any(obj -> !obj.isFulfilled)
and when that condition was hit, it would short-circuit the rest of the enumeration and immediately return true
.
Is there any such thing in Swift?
Swift Higher-Order Functions Some of the best-known functions are map , compactMap , flatMap , reduce , filter , contains , sorted , forEach , and removeAll .
A higher-order function can be defined as a function that accepts one or more functions as arguments and returns a function as a result. In this article, we will discuss some swift higher-order functions, including forEach, map, CompactMap, flatMap, filter, reduce, sort, and sorted.
Sequence
(and in particular Collection
and Array
) has a (short-circuiting) contains(where:)
method taking a boolean predicate as argument. For example,
if array.contains(where: { $0 % 2 == 0 })
checks if the array contains any even number.
There is no "all" method, but you can use contains()
as well
by negating both the predicate and the result. For example,
if !array.contains(where: { $0 % 2 != 0 })
checks if all numbers in the array are even. Of course you can define a custom extension method:
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) -> Bool) -> Bool {
return !contains(where: { !predicate($0) } )
}
}
If you want to allow "throwing" predicates in the same way as the
contains
method then it would be defined as
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
return try !contains(where: { try !predicate($0) } )
}
}
Update: As James Shapiro correctly noticed, an allSatisfy
method has been added to the Sequence
type in Swift 4.2 (currently in beta), see
(Requires a recent 4.2 developer snapshot.)
One other thing that you can do in Swift that is similar to "short circuiting" in this case is to use the lazy
property of a collection, which would change your implementation to something like this:
myObjects.lazy.filter({ !$0.isFulfilled }).first != nil
It's not exactly the same thing you're asking for, but might help provide another option when dealing with these higher-order functions. You can read more about lazy
in Apple's docs. As of this edit the docs contain the following:
var lazy: LazyCollection> A view onto this collection that provides lazy implementations of normally eager operations, such as map and filter.
var lazy: LazySequence> A sequence containing the same elements as this sequence, but on which some operations, such as map and filter, are implemented lazily.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With