Skip to content

Commit

Permalink
[Swift 4.2] Update Shuffle
Browse files Browse the repository at this point in the history
  • Loading branch information
subdan committed Oct 3, 2018
1 parent 4d50254 commit 7457400
Show file tree
Hide file tree
Showing 3 changed files with 4 additions and 18 deletions.
8 changes: 2 additions & 6 deletions Shuffle/README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ You should see three different arrangements -- or [permutations](../Combinatoric

This shuffle works *in place*, it modifies the contents of the original array. The algorithm works by creating a new array, `temp`, that is initially empty. Then we randomly choose an element from the original array and append it to `temp`, until the original array is empty. Finally, the temporary array is copied back into the original one.

> **Note:** `random()` is a helper function that returns a random integer between 0 and the given maximum.
This code works just fine but it's not very efficient. Removing an element from an array is an **O(n)** operation and we perform this **n** times, making the total algorithm **O(n^2)**. We can do better!

## The Fisher-Yates / Knuth shuffle
Expand All @@ -45,7 +43,7 @@ Here is a much improved version of the shuffle algorithm:
extension Array {
public mutating func shuffle() {
for i in stride(from: count - 1, through: 1, by: -1) {
let j = random(i + 1)
let j = Int.random(in: 0...i)
if i != j {
swap(&self[i], &self[j])
}
Expand All @@ -56,8 +54,6 @@ extension Array {

Again, this picks objects at random. In the naive version we placed those objects into a new temporary array so we could keep track of which objects were already shuffled and which still remained to be done. In this improved algorithm, however, we'll move the shuffled objects to the end of the original array.

> **Note**: When you write `random(x)`, the largest number it will return is `x - 1`. We want to have `j <= i`, not `j < i`, so the largest number from the random number generator needs to be `i`, not `i - 1`. That's why we do `random(i + 1)`. If we didn't add that 1 to compensate, it would make some shuffle orders more likely to occur than others.
Let's walk through the example. We have the array:

[ "a", "b", "c", "d", "e", "f", "g" ]
Expand Down Expand Up @@ -99,7 +95,7 @@ Here is the code:
public func shuffledArray(_ n: Int) -> [Int] {
var a = [Int](repeating: 0, count: n)
for i in 0..<n {
let j = random(i + 1)
let j = Int.random(in: 0...i)
if i != j {
a[i] = a[j]
}
Expand Down
5 changes: 0 additions & 5 deletions Shuffle/Shuffle.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
//: Playground - noun: a place where people can play

// last checked with Xcode 9.0b4
#if swift(>=4.0)
print("Hello, Swift 4!")
#endif

import Foundation

var list = [ "a", "b", "c", "d", "e", "f", "g" ]
Expand Down
9 changes: 2 additions & 7 deletions Shuffle/Shuffle.playground/Sources/Shuffle.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import Foundation

/* Returns a random integer between 0 and n-1. */
public func random(_ n: Int) -> Int {
return Int(arc4random_uniform(UInt32(n)))
}

extension Array {
/*
Randomly shuffles the array in-place
Expand All @@ -13,7 +8,7 @@ extension Array {
*/
public mutating func shuffle() {
for i in (1...count-1).reversed() {
let j = random(i + 1)
let j = Int.random(in: 0...i)
if i != j {
let t = self[i]
self[i] = self[j]
Expand All @@ -29,7 +24,7 @@ extension Array {
public func shuffledArray(_ n: Int) -> [Int] {
var a = Array(repeating: 0, count: n)
for i in 0..<n {
let j = random(i + 1)
let j = Int.random(in: 0...i)
if i != j {
a[i] = a[j]
}
Expand Down

0 comments on commit 7457400

Please sign in to comment.