Last active
August 29, 2015 14:16
-
-
Save JadenGeller/5d971f8088e9a6d81038 to your computer and use it in GitHub Desktop.
Swift Coalesce Function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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