Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Fisher-Yates shuffle as protocol extension on any random-access collection
// adapted from original, which was (c) 2015 Nate Cook, licensed under the MIT license
//
// Fisher-Yates shuffle as protocol extensions
import Darwin
extension CollectionType where Index: RandomAccessIndexType {
/// Return a copy of `self` with its elements shuffled
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
}
}
func arc4random_uniform<In: _SignedIntegerType, Out: _SignedIntegerType>(upto: In) -> Out {
precondition(upto < numericCast(UInt32.max))
return numericCast(Darwin.arc4random_uniform(numericCast(upto.toIntMax())))
}
extension MutableCollectionType where Index: RandomAccessIndexType {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
precondition(count < numericCast(UInt32.max))
// empty and single-element collections don't shuffle
if count < 2 { return }
for var i = 0 as Index.Distance;i != count;++i {
let j: Index.Distance = arc4random_uniform(count - i) + i
swap(&self[startIndex.advancedBy(i)], &self[startIndex.advancedBy(j)])
}
}
}
[1, 2, 3].shuffle()
// [2, 3, 1]
let fiveStrings = stride(from: 0, through: 100, by: 5).map(String.init).shuffle()
// ["20", "45", "70", "30", ...]
var numbers = [1, 2, 3, 4]
numbers.shuffleInPlace()
// [3, 2, 1, 4]
@natecook1000

This comment has been minimized.

Copy link

natecook1000 commented Sep 2, 2015

Need to add a check before the swap(...) to make sure i != j—that's a trapping error in Swift 2.0b6.

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.