Skip to content

Instantly share code, notes, and snippets.

@airspeedswift
Forked from natecook1000/shuffle.swift
Last active February 2, 2018 20:46
Show Gist options
  • Save airspeedswift/82978ccb29e0a989cc34 to your computer and use it in GitHub Desktop.
Save airspeedswift/82978ccb29e0a989cc34 to your computer and use it in GitHub Desktop.
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
Copy link

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