How to generate a random number in Swift without repeating the previous random number?

my solution, i think its easy to understand

var nums = [0,1,2,3,4,5,6,7,8,9]

while nums.count > 0 {

    // random key from array
    let arrayKey = Int(arc4random_uniform(UInt32(nums.count)))

    // your random number
    let randNum = nums[arrayKey] 

    // make sure the number isnt repeated
    nums.swapAt(arrayKey, nums.count-1)
    nums.removeLast()
}

Store the previous generated number in a variable and compare the generated number to the previous number. If they match generate a new random number. Repeat the generation of new numbers until they don't match.

var previousNumber: UInt32? // used in randomNumber() 

func randomNumber() -> UInt32 {
    var randomNumber = arc4random_uniform(10)
    while previousNumber == randomNumber {
        randomNumber = arc4random_uniform(10)
    }
    previousNumber = randomNumber
    return randomNumber
}

Update for Swift 5

Here is a nice trick to choose equally from the numbers that were not just previously chosen.

You have 10 numbers, but you only want to select from 9 numbers (0 through 9, but excluding the previous number). If you reduce your range by 1, you can select from 9 random numbers and then just replace a repeated number with the previous top number of the range. In this way, you only have to generate a single random number each time and you get uniformity.

This can be implemented as Int.random(in:excluding:) where you pass the value you want to exclude.

extension Int {
    static func random(in range: ClosedRange<Int>, excluding x: Int) -> Int {
        if range.contains(x) {
            let r = Int.random(in: Range(uncheckedBounds: (range.lowerBound, range.upperBound)))
            return r == x ? range.upperBound : r
        } else {
            return Int.random(in: range)
        }
    }
}

Example:

// Generate 30 numbers in the range 1...3 without repeating the
// previous number  
var r = Int.random(in: 1...3)
for _ in 1...30 {
    r = Int.random(in: 1...3, excluding: r)
    print(r, terminator: " ")
}
print()

1 3 2 1 2 1 3 2 1 3 1 3 2 3 1 2 3 2 1 3 2 1 3 1 2 3 2 1 2 1 3 2 3 2 1 3 1 2 1 2


Previous Answer:

var previousNumber = arc4random_uniform(10)   // seed the previous number

func randomNumber() -> UInt32 {
    var randomNumber = arc4random_uniform(9)  // generate 0...8
    if randomNumber == previousNumber {
        randomNumber = 9
    }
    previousNumber = randomNumber
    return randomNumber
}

Tags:

Swift