Generate a Swift array of nonrepeating random numbers

后端 未结 3 1907
猫巷女王i
猫巷女王i 2021-01-20 01:47

I\'d like to generate multiple different random numbers in Swift. Here is the procedure.

  1. Set up an empty array
  2. Generate a random number
  3. Ch

3条回答
  •  伪装坚强ぢ
    2021-01-20 02:36

    The construct you’re looking for with your approach might be something like:

    var temp: [Int] = []
    while temp.count < 4 {
        var randomNumber: Int
        do {
            randomNumber = randomInt(1, 5)
        } while contains(temp, randomNumber)
        temp.append(randomNumber)
    }
    

    This will be fine for tiny ranges like yours, but for larger ranges it will be very slow, because for the last few numbers you are waiting for the random number to hit precisely the remaining handful of possibilities. I just tried generating from a range of 200 in a playground and it took 9 seconds.

    If you want a random selection of numbers with guaranteed coverage over a range, you could generate it like by taking that range and shuffling it, like this:

    func shuffle(source: S) -> [S.Generator.Element] {
        var rangen = GeneratorOf { arc4random() }
        let a = Array(Zip2(rangen, source))
        return a.sorted { $0.0 < $1.0 }.map { $0.1 }
    }
    
    let min = 1, max = 5
    shuffle(min...max)
    

    If you want a selection of n non-repeating random numbers from a range 0.., there’s a particularly pretty algorithm to do this that generates an ascending sequence of random numbers from that range:

    func randomGeneratorOf(#n: Int, #from: Int) -> GeneratorOf {
    
        var select = UInt32(n)
        var remaining = UInt32(from)
        var i = 0
    
        return GeneratorOf {
            while i < from {
                if arc4random_uniform(remaining) < select {
                    --select
                    --remaining
                    return i++
                }
                else {
                    --remaining
                    ++i
                }
            }
            return nil
        }
    }
    

    Which you could use like so:

    let engines = [
        "Duck","Emily","Gordon","Henry", "Mavis",
        "Belle","James","Edward","Thomas","Toby"
    ]
    
    let picks = Array(randomGeneratorOf(n: 3, from: engines.count))
    
    for engine in PermutationGenerator(elements: engines, indices: picks) {
        println(engine)
    }
    

提交回复
热议问题