19

I'm just starting to learn Swift.

I'm attempting to create an array of several random numbers, and eventually sort the array. I'm able to create an array of one random number, but what's the best way to iterate this to create an array of several random numbers?

func makeList() {
   var randomNums = arc4random_uniform(20) + 1

    let numList = Array(arrayLiteral: randomNums)

}

makeList()
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
eloist
  • 465
  • 3
  • 10
  • 22
  • 1
    Define "several", do you know about "for loops"? – Larme Jan 25 '15 at 18:56
  • yes, i know for loops in javascript. I suppose I'd like to create a for loop that iterates 5 times, just for example's sake. – eloist Jan 25 '15 at 19:00
  • possible duplicate of [shortest code to create an array of random numbers in swift?](http://stackoverflow.com/questions/27809897/shortest-code-to-create-an-array-of-random-numbers-in-swift) – Vinzzz Jan 25 '15 at 19:19

5 Answers5

30

In Swift 4.2 there is a new static method for fixed width integers that makes the syntax more user friendly:

func makeList(_ n: Int) -> [Int] {
    return (0..<n).map { _ in .random(in: 1...20) }
}

Edit/update: Swift 5.1 or later

We can also extend Range and ClosedRange and create a method to return n random elements:

extension RangeExpression where Bound: FixedWidthInteger {
    func randomElements(_ n: Int) -> [Bound] {
        precondition(n > 0)
        switch self {
        case let range as Range<Bound>: return (0..<n).map { _ in .random(in: range) }
        case let range as ClosedRange<Bound>: return (0..<n).map { _ in .random(in: range) }
        default: return []
        }
    }
}

extension Range where Bound: FixedWidthInteger {
    var randomElement: Bound { .random(in: self) }
}

extension ClosedRange where Bound: FixedWidthInteger {
    var randomElement: Bound { .random(in: self) }
}

Usage:

let randomElements = (1...20).randomElements(5)  // [17, 16, 2, 15, 12]
randomElements.sorted() // [2, 12, 15, 16, 17]

let randomElement = (1...20).randomElement   // 4 (note that the computed property returns a non-optional instead of the default method which returns an optional)

let randomElements = (0..<2).randomElements(5)  // [1, 0, 1, 1, 1]
let randomElement = (0..<2).randomElement   // 0

Note: for Swift 3, 4 and 4.1 and earlier click here.

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
21

Ok, this is copy/paste of a question asked elsewhere, but I think I'll try to remember that one-liner:

var randomArray = map(1...100){_ in arc4random()}

(I love it!)

If you need a random number with an upperBound (exclusive), use arc4random_uniform(upperBound).

E.g.: random number between 0 and 99: arc4random_uniform(100)

Swift 2 update

var randomArray = (1...100).map{_ in arc4random()}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vinzzz
  • 11,746
  • 5
  • 36
  • 42
  • How would you limit this to only get 10 numbers? but with map(1...100) and preferably 10 UNIQUE numbers (non repeating) – Ace Green May 30 '15 at 01:58
  • Wait the above literally spits out random numbers. as in 100 elements of random numbers [1852894657, 278174301, 2558743979, 3659809261, 1696046131, 2549863704, 1571828145] – Ace Green May 30 '15 at 02:17
  • You're right, I was using the `arc4random()` function, but you can use `arc4random_uniform(100)`. Answer edited! – Vinzzz May 30 '15 at 11:31
  • so whats the map(1...100) for then if you do arc4random_uniform(100) – Ace Green May 30 '15 at 13:06
  • arc4random_uniform(100) returns a SINGLE random number. 1...100 is a Range (for sake of understanding, consider it an array). And `map` ... well it's the map function ! (look for functional programming to learn more about it). It applies to all members of the range. So every number between 1 & 100 is mapped to a random number between 0 & 99. Et voilà : you've got an array of 100 random numbers between 0 & 99! :) See the SO link I provided in my answer for further explanation. – Vinzzz May 31 '15 at 18:30
  • Did you try this? I get the above which is not what I want. I want an array of 10 random numbers that are between 0-6000. So you are saying I should do var randomArray = map(1...10){_ in arc4random(6000)} – Ace Green May 31 '15 at 18:56
  • Cannot find an overload for 'map' that accepts an argument list of type '(Range, (_) -> _)' – Ace Green May 31 '15 at 19:02
16

Swift 5

This creates an array of size 5, and whose elements range from 1 to 10 inclusive.

let arr = (1...5).map( {_ in Int.random(in: 1...10)} )
remykarem
  • 2,251
  • 22
  • 28
5

Swift 4.2 or later

func makeList(_ n: Int) -> [Int] {
    return (0..<n).map{ _ in Int.random(in: 1 ... 20) }
}

let list = makeList(5)  //[11, 17, 20, 8, 3]
list.sorted() // [3, 8, 11, 17, 20]
Eugene
  • 221
  • 3
  • 6
2

How about this? Works in Swift 5 and Swift 4.2:

public extension Array where Element == Int {
    static func generateRandom(size: Int) -> [Int] {
        guard size > 0 else {
            return [Int]()
        }
        return Array(0..<size).shuffled()
    }
}

Usage:

let array = Array.generateRandom(size: 10)
print(array)

Prints e.g.:

[7, 6, 8, 4, 0, 3, 9, 2, 1, 5]

The above approach gives you unique numbers. However, if you need redundant values, use the following implementation:

public extension Array where Element == Int {
    static func generateRandom(size: Int) -> [Int] {
        guard size > 0 else {
            return [Int]()
        }
        var result = Array(repeating: 0, count: size)
        for index in 0..<result.count {
            result[index] = Int.random(in: 0..<size)
        }
        return result
    }
}

A shorter version of the above using map():

public extension Array where Element == Int {
    static func generateRandom(size: Int) -> [Int] {
        guard size > 0 else {
            return [Int]()
        }
        var result = Array(repeating: 0, count: size)
        return result.map{_ in Int.random(in: 0..<size)}
    }
}
Karoly Nyisztor
  • 3,505
  • 1
  • 26
  • 21