Generate an array of unique random numbers within the included range

I'm trying to write a function in Apple Swift (iOS) that will generate any given number of unique random numbers that are within a given open range, say between 0 and 10. Therefore, if I say that I want 5 unique random numbers between 0 and 10, it will return an array with [7, 10, 2, 3, 0] or [7, 10, 2, 8, 0], etc.

I have this part working with:

// Returns an array of unique numbers
func uniqueRandoms(numberOfRandoms: Int, minNum: Int, maxNum: UInt32) -> [Int] {

    var uniqueNumbers = [Int]()

    while uniqueNumbers.count < numberOfRandoms {

        let randomNumber = Int(arc4random_uniform(maxNum + 1)) + minNum
        var found = false

        for var index = 0; index < uniqueNumbers.count; ++index {
                if uniqueNumbers[index] == randomNumber {
                    found = true
                    break
                }
        }

        if found == false {
            uniqueNumbers.append(randomNumber)
        }

    }

    return uniqueNumbers
}

print(uniqueRandoms(5, minNum: 0, maxNum: 10))

Now I want to add the ability to blacklist a single number within this range, which I do not want. Let's say I still want 5 unique random numbers from 0 to 10, but I don't want it to ever include 8.

This part causes an infinite loop (25% + time or more), and I can’t understand why? Here is what I have:

var blackListNum = 8

// Returns an array of unique numbers
func uniqueRandoms(numberOfRandoms: Int, minNum: Int, maxNum: UInt32, checkBlackList: Bool = false) -> [Int] {

    var uniqueNumbers = [Int]()

    while uniqueNumbers.count < numberOfRandoms {

        let randomNumber = Int(arc4random_uniform(maxNum + 1)) + minNum
        var found = false

        for var index = 0; index < uniqueNumbers.count; ++index {
            if checkBlackList == false {
                if uniqueNumbers[index] == randomNumber {
                    found = true
                    break
                }
            } else {
                if uniqueNumbers[index] == randomNumber || uniqueNumbers[index] == blackListNum  {
                    found = true
                    break
                }
            }
        }

        if found == false {
            uniqueNumbers.append(randomNumber)
        }

    }

    return uniqueNumbers
}

print(uniqueRandoms(5, minNum: 0, maxNum: 10, checkBlackList: true))

, , Swift, , , , . - . , , , , .. .

+4
6

, Set , :

func uniqueRandoms(numberOfRandoms: Int, minNum: Int, maxNum: UInt32) -> [Int] {
    var uniqueNumbers = Set<Int>()
    while uniqueNumbers.count < numberOfRandoms {
        uniqueNumbers.insert(Int(arc4random_uniform(maxNum + 1)) + minNum)
    }
    return Array(uniqueNumbers).shuffle
}

print(uniqueRandoms(5, minNum: 0, maxNum: 10))

func uniqueRandoms(numberOfRandoms: Int, minNum: Int, maxNum: UInt32, blackList: Int?) -> [Int] {
    var uniqueNumbers = Set<Int>()
    while uniqueNumbers.count < numberOfRandoms {
        uniqueNumbers.insert(Int(arc4random_uniform(maxNum + 1)) + minNum)
    }
    if let blackList = blackList {
        if uniqueNumbers.contains(blackList) {
            while uniqueNumbers.count < numberOfRandoms+1 {
                uniqueNumbers.insert(Int(arc4random_uniform(maxNum + 1)) + minNum)
            }
            uniqueNumbers.remove(blackList)
        }
    }
    return Array(uniqueNumbers).shuffle
}

uniqueRandoms(3, minNum: 0, maxNum: 10, blackList: 8)  // [0, 10, 7]

, :

extension Array {
    var shuffle:[Element] {
        var elements = self
        for index in 0..<elements.count {
            let anotherIndex = Int(arc4random_uniform(UInt32(elements.count-index)))+index
            if anotherIndex != index {
                swap(&elements[index], &elements[anotherIndex])
            }
        }
        return elements
    }
}
+8

, , :

// create an array of 0 through 10
var nums = Array(0...10)

// remove the blacklist number
nums.removeAtIndex(nums.indexOf(8)!)

var randoms = [Int]()
for _ in 1...5 {
    let index = Int(arc4random_uniform(UInt32(nums.count)))
    randoms.append(nums[index])
    nums.removeAtIndex(index)
}

, , . , , , .

+7

Swift 4.0

, , , , , , (, , 50% ).

, .

, , , , , .

func randomNumber(between lower: Int, and upper: Int) -> Int {
    return Int(arc4random_uniform(UInt32(upper - lower))) + lower
}

func generateRandomUniqueNumbers1(forLowerBound lower: Int, andUpperBound upper:Int, andNumNumbers iterations: Int) -> [Int] {
    guard iterations <= (upper - lower) else { return [] }
    var numbers: [Int] = []
    (0..<iterations).forEach { _ in
        var nextNumber: Int
        repeat {
            nextNumber = randomNumber(between: lower, and: upper)
        } while numbers.contains(nextNumber)
        numbers.append(nextNumber)
    }
    return numbers
}

, vacawama. , . , .

func generateRandomUniqueNumbers2(forLowerBound lower: Int, andUpperBound upper:Int, andNumNumbers iterations: Int) -> [Int] {
    guard iterations <= (upper - lower) else { return [] }
    var indices: [Int] = (lower..<upper).sorted()
    var numbers: [Int] = []
    (0..<iterations).forEach { _ in
        let nextNumberIndex = randomNumber(between: 0, and: indices.count)
        let nextNumber: Int = indices[nextNumberIndex]
        indices.remove(at: nextNumberIndex)
        numbers.append(nextNumber)
    }
    return numbers
}

, . Set, .

func generateRandomUniqueNumbers3(forLowerBound lower: Int, andUpperBound upper:Int, andNumNumbers iterations: Int) -> [Int] {
    guard iterations <= (upper - lower) else { return [] }
    var numbers: Set<Int> = Set<Int>()
    (0..<iterations).forEach { _ in
        let beforeCount = numbers.count
        repeat {
            numbers.insert(randomNumber(between: lower, and: upper))
        } while numbers.count == beforeCount
    }
    return numbers.map{ $0 }
}

, 1 , 100 , , 90 . , 80- , 20% - , . , 5000 , 90% .

, 2 , , .

, 3. , - .

XCTest . 2 : . - , - , (.. 80 80 , 50% , 40 80).

9 3 (5, 250 12 500) (10%, 50% 90%). , , , ( 2500 ).

:

1

(Population: 5;      Density: 10%; Iterations: 2,500): 0.0056s
(Population: 250;    Density: 10%; Iterations: 50)   : 0.0046s
(Population: 12,500; Density: 10%; Iterations: 10)   : 1.33s
(Population: 5;      Density: 50%; Iterations: 2,500): 0.0131s
(Population: 250;    Density: 50%; Iterations: 50)   : 0.0912s
(Population: 12,500; Density: 50%; Iterations: 1)    : 4.09s
(Population: 5;      Density: 90%; Iterations: 2,500): 0.0309s
(Population: 250;    Density: 90%; Iterations: 10)   : 0.0993s
(Population: 12,500; Density: 90%; Iterations: 1)    : 23s

2

(Population: 5;      Density: 10%; Iterations: 2,500): 0.0184s
(Population: 250;    Density: 10%; Iterations: 50)   : 0.0086s
(Population: 12,500; Density: 10%; Iterations: 10)   : 0.103s
(Population: 5;      Density: 50%; Iterations: 2,500): 0.0233s
(Population: 250;    Density: 50%; Iterations: 50)   : 0.0125s
(Population: 12,500; Density: 50%; Iterations: 1)    : 0.0209s
(Population: 5;      Density: 90%; Iterations: 2,500): 0.0242s
(Population: 250;    Density: 90%; Iterations: 10)   : 0.0046s
(Population: 12,500; Density: 90%; Iterations: 1)    : 0.0278s

3

(Population: 5;      Density: 10%; Iterations: 2,500): 0.00672s
(Population: 250;    Density: 10%; Iterations: 50)   : 0.0024s
(Population: 12,500; Density: 10%; Iterations: 10)   : 0.0148s
(Population: 5;      Density: 50%; Iterations: 2,500): 0.0134s
(Population: 250;    Density: 50%; Iterations: 50)   : 0.00769s
(Population: 12,500; Density: 50%; Iterations: 1)    : 0.00789s
(Population: 5;      Density: 90%; Iterations: 2,500): 0.0209s
(Population: 250;    Density: 90%; Iterations: 10)   : 0.00397s
(Population: 12,500; Density: 90%; Iterations: 1)    : 0.0163s

(Case 1): Solution 1 is fastest; then 3; then 2
(Case 2): Solution 3 is fastest; then 1; then 2
(Case 3): Solution 3 is fastest; then 2; then 3
(Case 4): Solution 1 is fastest; then 3; then 2
(Case 5): Solution 3 is fastest; then 2; then 1
(Case 6): Solution 3 is fastest; then 2; then 1
(Case 7): Solution 3 is fastest; then 2; then 1
(Case 8): Solution 3 is fastest; then 2; then 1
(Case 9): Solution 3 is fastest; then 2; then 1

, . , 2 , . , 1 25 250 , 2 3, .

, (.. 2 12 500), 1 , 77% , 3, , 2. , , , , , 1 2 .

3 . , .

+2

. SwiftStub:

extension Array {
    func shuffle() -> Array<Element> {
        var newArray = self

        for i in 0..<newArray.count {
            let j = Int(arc4random_uniform(UInt32(newArray.count)))
            guard i != j else { continue }
            swap(&newArray[i], &newArray[j])
        }

        return newArray
    }
}

func uniqueRandoms(count: Int, inRange range: Range<Int>, blacklist: [Int] = []) -> [Int] {
    var r = [Int](range)
        .filter{ !blacklist.contains($0) }
        .shuffle()

    return Array(r[0..<count])
}

let x = uniqueRandoms(5, inRange: 1...10000)
let y = uniqueRandoms(5, inRange: 1...10, blacklist: [2,4,6,8,10])
print(x)
print(y)

filter .

shuffle - , Array. , .

return Array(r[0..<count]) Slice .

, , count. , :

let a = uniqueRandoms(10, inRange: 1...5)
let b = uniqueRandoms(3, inRange: 1...5, blacklist: [1,2,3,4])

, OP.

+1
// 1st version where I only blacklisted 8
var randomNumbers = [Int]()
for _ in 1...7 {
    var number = Int(arc4random_uniform(8))+1
    while  randomNumbers.contains(number) || number == 8{
        number = Int(arc4random_uniform(8))+1
    }
    randomNumbers.append(number)
}
print(randomNumbers)

// 2nd version where I created an array of blacklisted numbers
var randomNumbers = [Int]()
var blackList = [8, 5, 2, 7]
for _ in 1...3 {
    var number = Int(arc4random_uniform(10))+1
    while  randomNumbers.contains(number) || blackList.contains(number){
        number = Int(arc4random_uniform(10))+1
    }
    randomNumbers.append(number)
}
print(randomNumbers)

2 "randomNumbers" "blackList", for for. "" . "" , while .contians, , "" "randomNumbers" "number" "blackList", - "number" , "number" , "" . randomNumbers.append() "" "randomNumbers" , .

0

:

  let UniqueIdNumber = CFUUIDCreateString(nil, CFUUIDCreate(nil))
-1

Source: https://habr.com/ru/post/1608919/


All Articles