Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Swift Coalesce Function
/*
* coalesce takes in a list of optional values
* and returns the first one that is not nil
*/
func coalesce<T>(all: @autoclosure () -> T? ...) -> T? {
for f: () -> T? in all {
if let x = f() { return x }
}
return nil
}
/*
* Just like coalesce, but allows you to specify an additional acceptance
* criteria in addition to being not nil
*/
func coalesce<T>(approve: T -> Bool, all: @autoclosure () -> T? ...) -> T? {
for f: () -> T? in all {
if let x = f() {
if approve(x) { return x }
}
}
return nil
}
// Example
// Note we are using null instead of nil because a nil *literal*
// cannot be passed into an autoclosure (a nil value can be)
// Luckily, that wouldn't be very useful anyway except for demonstration
let null = Optional<Int>.None
let x = coalesce(2, 3, null, 4) // -> 2
let y = coalesce(nilValue, null, null, 4) // -> 4
let z = coalesce(null, null) // -> nil
// As a more complex example, not that we use autoclosures
// so that unneeded expensive function calls are not made
func f() -> Int? {
println("Hello world")
return nil
}
let a = coalesce(f(), 3) // prints "Hello world"; -> 3
let b = coalesce(3, f()) // does not print; -> 3
func g() -> Int? {
println("Bye world")
return 2
}
let c = coalesce(f(), g()) // prints "Hello world"; prints "Bye world"; -> 2
let d = coalesce(g(), f()) // prints "Bye world"; -> 2
// Now we will now demonstrate the more complex coalesce function
let whoa = coalesce({num in num > 2}, null, 1, f(), g(), 4) // prints "Hello world"; prints "Bye world"; -> 4
*/
/*
* Used as a helper for a coalesce function with random order support
* Feel free to provide your own
*/
extension Array {
func shuffled() -> [T] {
var list = self
for i in 0..<(list.count - 1) {
let j = Int(arc4random_uniform(UInt32(list.count - i))) + i
swap(&list[i], &list[j])
}
return list
}
}
/*
* Adds an additional parameter to our coalesce function that allows us to randomize the
* order of execution. This is useful when you don't care which result you get, as long as
* you get one.
* Note: [Obviously] Not deterministic!
*/
func coalesce<T>(approve: T -> Bool, randomize: Bool, all: @autoclosure () -> T? ...) -> T? {
for f: () -> T? in (randomize ? all.shuffled() : all) {
if let x = f() {
if approve(x) { return x }
}
}
return nil
}
// Example
coalesce({num in num > 5}, 1, 2, 3, 4, 5, 6, 7, 8, 9)
// -> 5
// OR -> 6
// OR -> 8
// OR -> 9
// (with equal probability)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.