生成一个非重复随机数的Swift数组

时间:2022-08-27 00:23:24

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

我想在Swift中生成多个不同的随机数。这是程序。

  1. Set up an empty array
  2. 设置一个空数组

  3. Generate a random number
  4. 生成一个随机数

  5. Check if the array is empty
    a. If the array is empty, insert the random number
    b. If the array is not empty, compare the random number to the numbers in array
    i. If the numbers are the same, repeat 2
    ii. if the numbers are not the same, insert the random number and repeat 2

    检查阵列是否为空a。如果数组为空,请插入随机数b。如果数组不为空,则将随机数与数组i中的数字进行比较。如果数字相同,则重复2 ii。如果数字不相同,请插入随机数并重复2

    import UIKit 
    
    //the random number generator
    func randomInt(min: Int, max:Int) -> Int {
        return min + Int(arc4random_uniform(UInt32(max - min + 1)))
    }
    
    var temp = [Int]()
    for var i = 0; i<4; i++ {
      var randomNumber = randomInt(1, 5)
      if temp.isEmpty{
        temp.append(randomNumber)
      } else {
      //I don't know how to continue...
     }
    }
    

3 个解决方案

#1


4  

If you use your method the problem is, that you will create a new random-number each time. So you possibly could have the same random-number 4 times and so your array will only have one element.

如果你使用你的方法问题是,你每次都会创建一个新的随机数。所以你可能有4次相同的随机数,所以你的数组只有一个元素。

So, if you just want to have an array of numbers from within a specific range of numbers (for example 0-100), in a random order, you can first fill an array with numbers in 'normal' order. For example with for loop etc:

因此,如果您只想在特定数字范围内(例如0-100)拥有一个数字数组,则可以按照随机顺序,以“正常”顺序填充数字。例如使用for循环等:

var min = 1
var max = 5
for var i = min; i<= max; i++ {
    temp.append(i)
}

After that, you can use a shuffle method to shuffle all elements of the array with the shuffle method from this answer:

之后,您可以使用shuffle方法使用此答案中的shuffle方法对数组的所有元素进行洗牌:

func shuffle<C: MutableCollectionType where C.Index == Int>(var list: C) -> C {
    let count = countElements(list)
    for i in 0..<(count - 1) {
        let j = Int(arc4random_uniform(UInt32(count - i))) + i
        swap(&list[i], &list[j])
    }
    return list
}

Ater that you can do something like that:

Ater,你可以这样做:

shuffle(temp)        // e.g., [3, 1, 2, 4, 5]

#2


1  

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.

这对于像你这样的小范围来说会很好,但是对于较大的范围来说它会非常慢,因为对于最后几个数字,你正在等待随机数精确地击中剩下的一些可能性。我只是尝试在操场上从200的范围内进行生成,花了9秒钟。

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<S: SequenceType>(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..<m, there’s a particularly pretty algorithm to do this that generates an ascending sequence of random numbers from that range:

如果你想要从范围0 .. 中选择n个非重复随机数,那么有一个特别漂亮的算法可以从这个范围产生一个递增的随机数序列:

func randomGeneratorOf(#n: Int, #from: Int) -> GeneratorOf<Int> {

    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)
}

#3


1  

Below is my suggestion. I like this way since it is short and simple :)

以下是我的建议。我喜欢这种方式,因为它简短而简单:)

let totalCount: Int = 150 //Any number you asssign
var randomNumArray: [Int] = []
var i = 0
while randomNumArray.count < totalCount {
    i++
    let rand = Int(arc4random_uniform(UInt32(totalCount)))
    for(var ii = 0; ii < totalCount; ii++){
        if randomNumArray.contains(rand){
            print("do nothing")
        } else {
            randomNumArray.append(rand)
        }
    }
}

#1


4  

If you use your method the problem is, that you will create a new random-number each time. So you possibly could have the same random-number 4 times and so your array will only have one element.

如果你使用你的方法问题是,你每次都会创建一个新的随机数。所以你可能有4次相同的随机数,所以你的数组只有一个元素。

So, if you just want to have an array of numbers from within a specific range of numbers (for example 0-100), in a random order, you can first fill an array with numbers in 'normal' order. For example with for loop etc:

因此,如果您只想在特定数字范围内(例如0-100)拥有一个数字数组,则可以按照随机顺序,以“正常”顺序填充数字。例如使用for循环等:

var min = 1
var max = 5
for var i = min; i<= max; i++ {
    temp.append(i)
}

After that, you can use a shuffle method to shuffle all elements of the array with the shuffle method from this answer:

之后,您可以使用shuffle方法使用此答案中的shuffle方法对数组的所有元素进行洗牌:

func shuffle<C: MutableCollectionType where C.Index == Int>(var list: C) -> C {
    let count = countElements(list)
    for i in 0..<(count - 1) {
        let j = Int(arc4random_uniform(UInt32(count - i))) + i
        swap(&list[i], &list[j])
    }
    return list
}

Ater that you can do something like that:

Ater,你可以这样做:

shuffle(temp)        // e.g., [3, 1, 2, 4, 5]

#2


1  

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.

这对于像你这样的小范围来说会很好,但是对于较大的范围来说它会非常慢,因为对于最后几个数字,你正在等待随机数精确地击中剩下的一些可能性。我只是尝试在操场上从200的范围内进行生成,花了9秒钟。

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<S: SequenceType>(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..<m, there’s a particularly pretty algorithm to do this that generates an ascending sequence of random numbers from that range:

如果你想要从范围0 .. 中选择n个非重复随机数,那么有一个特别漂亮的算法可以从这个范围产生一个递增的随机数序列:

func randomGeneratorOf(#n: Int, #from: Int) -> GeneratorOf<Int> {

    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)
}

#3


1  

Below is my suggestion. I like this way since it is short and simple :)

以下是我的建议。我喜欢这种方式,因为它简短而简单:)

let totalCount: Int = 150 //Any number you asssign
var randomNumArray: [Int] = []
var i = 0
while randomNumArray.count < totalCount {
    i++
    let rand = Int(arc4random_uniform(UInt32(totalCount)))
    for(var ii = 0; ii < totalCount; ii++){
        if randomNumArray.contains(rand){
            print("do nothing")
        } else {
            randomNumArray.append(rand)
        }
    }
}