从范围生成Swift中的唯一随机数列表

时间:2018-04-02 16:08:06

标签: swift random arc4random

我想写一个应该返回整数列表的函数。整数列表大小和最大随机数将由用户定义,用户将通过函数参数。我的特殊要求是,整数列表不能多余 我使用<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> </head> <body onload="startGame()"> <div style="text-align:center;width:480px;"> <button onclick="moveup()">UP</button><br><br> <button onclick="moveleft()">LEFT</button> <button onclick="moveright()">RIGHT</button><br><br> <button onclick="movedown()">DOWN</button> </div> <p>If you click a button the red square will start moving. Click the same button many times, and it will move faster and faster.</p> </body> </html>的方法:

Array

问题:有时我会通过这种方法获得重复值 我知道swift func getRandomNumbers(maxNumber: Int, listSize: Int)-> [Int]{ var randomNumbers = [Int]() for _ in 1...listSize{ let randomNumber = Int(arc4random_uniform(UInt32(listSize))) randomNumbers.append(randomNumber) } return randomNumbers } 没有重复值。

我使用Set的方法:

Set

问题:有时func getRandomNumbers(maxNumber: Int, listSize: Int)-> Set<Int>{ var randomNumbers = Set<Int>() for _ in 1...listSize{ let randomNumber = Int(arc4random_uniform(UInt32(listSize))) randomNumbers.insert(randomNumber) } return randomNumbers } 大小小于用户定义的大小。

5 个答案:

答案 0 :(得分:1)

你需要使用while count小于listSize而不是for循环,而不是你需要将maxNumber加一而不是listSize传递给arc4random_uniform:

func getRandomNumbers(maxNumber: Int, listSize: Int)-> Set<Int> {
    var randomNumbers = Set<Int>()
    while randomNumbers.count < listSize {
        let randomNumber = Int(arc4random_uniform(UInt32(maxNumber+1)))
        randomNumbers.insert(randomNumber)
    }
    return randomNumbers
}

getRandomNumbers(maxNumber: 10, listSize: 3)  // {5, 7, 0}

答案 1 :(得分:1)

当您获得重复的随机数时会发生这种情况。您可以检查randomNumbers.count并生成随机数,直到它到达listSize,而不是生成listSize随机数。

答案 2 :(得分:1)

这里有两个问题:

  1. 您没有生成足够的数字。您需要继续生成随机数,直到您的集合足够大:

    func getRandomNumbers(maxNumber: Int, listSize: Int)-> [Int] {
        var randomNumbers = Set<Int>()
        while randomNumbers.count < listSize {
            let randomNumber = Int(arc4random_uniform(UInt32(maxNumber+1)))
            randomNumbers.insert(randomNumber)
        }
        return randomNumbers
    }
    
  2. 您通过将随机数放入排序集选择中来偏向您,这是非常可预测的。您应该将数字附加到数组(以保持它们的生成顺序),同时仍然并行使用集合,以实现快速重复数据删除:

    func getRandomNumbers(maxNumber: Int, listSize: Int)-> [Int] {
        precondition(listSize < maxNumber, "Cannot generate a list of \(listSize) unique numbers, if they all have to be less than \(maxNumber)")
    
        var randomNumbers = (array: [Int](), set: Set<Int>())
    
        while randomNumbers.set.count < listSize {
            let randomNumber = Int(arc4random_uniform(UInt32(maxNumber+1)))
            if randomNumbers.set.insert(randomNumber).inserted { // If the number is unique
                randomNumbers.array.append(randomNumber) // then also add it to the arary
            }
        }
    
        return randomNumbers.array
    }
    

答案 3 :(得分:1)

这是另一种可能性。我不是声称这是最好的,但在我看来,IndexSet可能是一个解决问题的好方法(基本上,这个想法书呆子,我必须找到答案),这就是我想出来的。

func getRandomNumbers(maxNumber: Int, listSize: Int)-> [Int]{
    guard maxNumber < listSize else { return [] }
    var indexSet = IndexSet(integersIn: 0...listSize)
    var randomInts = [Int]()

    while randomInts.count < maxNumber {
        guard let currentInt = indexSet.integerLessThanOrEqualTo(Int(arc4random_uniform(UInt32(listSize)))) else {
            continue
        }
        randomInts.append(currentInt)
        indexSet.remove(currentInt)
    }
    return randomInts
}

我们的想法是创建一个覆盖0到请求的最大值的IndexSet,然后从该集合中随机删除元素,直到你有足够的元素。它通过在使用集合时删除整数来避免重复。 IndexSet实际上不是Set,它是存储一堆唯一整数的有效方式,因此它获得了Set的唯一性而没有实际创建{{1}包含范围内的所有整数。

答案 4 :(得分:1)

Swift 5 版本实现

extension Int {

    static func getUniqueRandomNumbers(min: Int, max: Int, count: Int) -> [Int] {
        var set = Set<Int>()
        while set.count < count {
            set.insert(Int.random(in: min...max))
        }
        return Array(set)
    }

}

例如:

let uniqueNumbers = Int.getUniqueRandomNumbers(min: 1000, max: 1500, count: 10)

示例结果:

[1454, 1105, 1305, 1176, 1498, 1127, 1310, 1209, 1373, 1198]