I want to use arc4random to generate array of 30 different numbers, so that there is no repeating in it. How can I do it?
-
3What have you tried so far?G. LC– G. LC2018-07-31 17:31:24 +00:00Commented Jul 31, 2018 at 17:31
-
I have tried to make for loop and to use array.contains(n) but it either doesn’t fill all 30 numbers or it repeats some of them. I am stucked.Vladimir Sukanica– Vladimir Sukanica2018-07-31 17:33:57 +00:00Commented Jul 31, 2018 at 17:33
-
1Possibly Related: stackoverflow.com/questions/32773593/…Ahmad F– Ahmad F2018-07-31 20:34:45 +00:00Commented Jul 31, 2018 at 20:34
4 Answers
Update:
Thanks to @Sulthan for his elegant thought (commented on Gereon's answer):
anyway, depending on the difference between limit and the number of generated elements this can have a terrible performance. The problem is the case when limit is close to the number of generated elements. Then it would be much better to take
1..<limitand shuffle it.
Which means that there is no even need to generate random Int. The simplest way I could think of is to do it as (Swift 4.2):
let randoms = Array(0..<30).shuffled()
therefore randoms is an array of Ints, contains 30 unique values from 0 to 29.
Less Than Swift 4.2:
However, if you are not using Swift 4.2, I would recommend to check this great answer for getting shuffled collection.
Ignored Solution:
You could achieve it like this:
var uniques = Set<UInt32>()
func generateUniqueUInt32() -> UInt32 {
let random = arc4random_uniform(31)
if !uniques.contains(random) {
uniques.insert(random)
return random
} else {
return generateUniqueUInt32()
}
}
let randomArray = Array(0..<30).map { _ in Int(generateUniqueUInt32()) }
Therefore randomArray is an array of Ints, contains 30 unique values from 0 to 29.
Swift 4.2:
You should replace:
let random = arc4random_uniform(31)
with:
let random = Int.random(in: 1..<30)
which means that generateUniqueUInt32 should return -directly- Int (and renamed to generateUniqueInt):
func generateUniqueInt() -> Int {
let random = Int.random(in: 1..<30)
if !uniques.contains(random) {
uniques.insert(random)
return random
} else {
return generateUniqueInt()
}
}
let randomArray = Array(0..<30).map { _ in generateUniqueInt() }
Comments
It may be a pretty heavy action but you can do like that:
var randomNumbers: [Int] = []
while randomNumbers.count != 30{
let number = Int(arc4random_uniform(1000) + 1)
if randomNumbers.contains(number) {
print("Already Exits")
}else{
randomNumbers.append(number)
}
}
replace "1000" for a range of number that you need. That function generated 30 different number between 0...1000
2 Comments
Use a Set to store the generated numbers so far
func thirtyUniqueRandomNumbers(_ limit: Int) -> [Int] {
var randoms = Set<Int>()
repeat {
let rnd = Int(arc4random_uniform(UInt32(limit)))
if !randoms.contains(rnd) {
randoms.insert(rnd)
}
} while randoms.count < 30
return randoms.map { $0 }
}
3 Comments
Int.random(in: 0 ... 10)?limit and the number of generated elements this can have a terrible performance. The problem is the case when limit is close to the number of generated elements. Then it would be much better to take 1..<limit and shuffle it.Here is a simple solution. Start a while loop. Within this loop generate a random number (between 0 and 1000). And then append the number into your array if the array doesn't contains the number.
func generateArrayOfRandomNumbers() -> [Int] {
var array: [Int] = []
while array.count < 30 {
let randomInt = Int.random(in: 0...1000)
guard !array.contains(randomInt) else { continue }
array.append(randomInt)
}
return array
}