Search This Blog

Sunday, July 1, 2018

Generating random and using It in Swift

Default Methods

For generating random numbers in swift, the following functions are used:
  • arc4random() returns a random integer number in the range of 0 to 4 294 967 295 (it is UInt32.max)
  • drand48() returns a random float point number in the range of 0.0 to 1.0
  • arc4random_uniform(N) returns a random integer number in the range of 0 to N - 1

Let's see examples of how this functions work:
arc4random() // 107985684

drand48() // 0.3964647737602753

arc4random_uniform(10) // 4
But what if we need to implement more advanced requirements for generating random numbers. Let's explore possible situations where we generating random numbers and using it.

Generate Random Integer with Upper Bound

For generating random integer in range between 0 and upper bound we use function

rc4random_uniform(N)

This function will return random integer number in the range of 0 to N - 1. So, for example, if N = 42 then maximum number that can be generate will be 41 and minimum will be 0.
rc4random_uniform(42)
This function takes one parameter of type UInt32 and returns value of type UInt32
func arc4random_uniform(_ __upper_bound: UInt32) -> UInt32
So, if you work with values of type Int you have to convert values to type UInt32 when parameter passed to function and convert back to Int when getting result.
let number: Int
number = Int(arc4random_uniform(42))

let inputNumer: Int = 100
let outputNumber: Int
outputNumber = Int(arc4random_uniform(UInt32(inputNumer)))
It is not very handy always do this conversion when generating random numbers. Let's make a function for this:
func random(n: Int) -> Int {
    return Int(arc4random_uniform(UInt32(n)))
}

let n: Int
n = random(n: 99)
This function takes one parameter of type Int and return result in range between 0 and N-1 of type Int.

To make it more useful we can create extension for type Int and generating of random integers will be availbale everywhere in code. We also can check for sign before passed parameter because UInt32 type is unsigned type and in case of negative value passed we need to get absolute value from input passed parameter. This method is static and will be available for whole Int type, there is no need to create instance of Int type.
extension Int {
    
    static func random(_ n: Int) -> Int {
        if n < 0 {
            return -Int(arc4random_uniform(UInt32(abs(n))))
        } else if n > 0 {
            return Int(arc4random_uniform(UInt32(n)))
        } else {
            return 0
        }
    }
}

Int.random(-100) // return in range between -99 and 0
But we can create also an instance method in extension. In this case instance of Int type will be used as upper bound for random number generation function.
extension Int {
   
    func random() -> Int {
        if n < 0 {
            return -Int(arc4random_uniform(UInt32(abs(self))))
        } else if n > 0 {
            return Int(arc4random_uniform(UInt32(self)))
        } else {
            return 0
        }
    }
}

65.random()

Generate Random Integer in Range (with Lower and Upper Bounds)

What if you need to get random number in special range, for example, between 15 and 25, or between 90 and 100, and etc. So, for that purpose we will write special function.
func randomInRange(lowerBound: Int, upperBound: Int) -> Int {
    guard lowerBound < upperBound else {
        return lowerBound
    }
    return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound + 1)))
}

randomInRange(lowerBound: 20, upperBound: 30)
This function will return random value in range between lowerBound and upperBound, both bounds are inclusive.

We also can use range as parameter, for example, like this 0..<100
func randomInRange(_ range: Range<Int>) -> Int {
    guard range.lowerBound < range.upperBound else {
        return range.lowerBound
    }
    return range.lowerBound + Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound + 1)))
}


randomInRange(0..<100) // will return in range between 0 and 99 inclusive
Range can be closed, for example, like this 0...100, for this we need to change type Range for ClosedRange
func randomInRange(_ range: ClosedRange<Int>) -> Int {
    guard range.lowerBound < range.upperBound else {
        return range.lowerBound
    }
    return range.lowerBound + Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound + 1)))
}


randomInRange(0...100) // will return in range between 0 and 100 inclusive
Now, we can go further and create extension for range. And even more, this extension will work as with normal ranges as with negative ranges.
extension Range where Bound == Int {
    
    var random: Int {
        var offset = 0
        if lowerBound < 0 {
            offset = abs(lowerBound)
        }
        let lower = UInt32(lowerBound + offset)
        let upper = UInt32(upperBound + offset)
        return Int(lower + arc4random_uniform(upper - lower + 1)) - offset
    }
}

(0..<123).random
(-500..<500).random

Generate Array of Random Numbers

We can create an array of random integer numbers by generating random numbers in for loop.
func generateArrayOfNumbers(count: Int, upperBound: Int) -> [Int] {
    var result = [Int]()
    for _ in 0..<count {
        result.append(Int.random(upperBound))
    }
    return result
}

generateArrayOfNumbers(count: 10, upperBound: 100)
For generating random numbers we can use, for example, extension for range that we wrote above.
func generateArrayOfNumbers(count: Int, range: Range<Int>) -> [Int] {
    var result = [Int]()
    for _ in 0..<count {
        result.append(range.random)
    }
    return result
}

generateArrayOfNumbers(count: 10, range: 0..<10)

One Line Generation
For generating array we can use map function for ranges. Every element of range will be used as iteration in a loop and random number will be generated and added to array.

For closed range
var randomArray = (1...10).map { _ in Int(arc4random_uniform(100)) }
Or for non-closed range
var randomArray = (1..<10).map { _ in Int(arc4random_uniform(100)) }

Generate Array of Unique(Non Repeating) Random Numbers

In case we need generate array of random numbers without repeating values we can use following strategies:

1. Using contains method of Array and repeat while loop
func uniqueRandomArray(count: Int, min: Int, max: Int) -> [Int] {
    guard count <= (max - min + 1) else {
        return []
    }
    var numbers = [Int]()
    for i in 1...count {
        var random: Int
        repeat {
            random = min + Int(arc4random_uniform(UInt32(max - min + 1)))
        } while numbers.contains(random)
        numbers.append(random)
    }
    return numbers

}

var randomArray = uniqueRandomArray(count: 10, min: 15, max: 55)
2. Using Set<Int> and while loop
func uniqueRandomArray(count: Int, min: Int, max: Int) -> [Int] {
    guard count <= (max - min + 1) else {
        return []
    }
    var numbers = Set<Int>()
    while numbers.count < count {
        let random = min + Int(arc4random_uniform(UInt32(max - min + 1)))
        numbers.insert(random)
    }
    return Array(numbers)
}

var randomArray = uniqueRandomArray(count: 50, min: 11, max: 99)
3. Using additional Array with numbers
func uniqueRandomArray(count: Int, min: Int, max: Int) -> [Int] {
    guard count <= (max - min + 1) else {
        return []
    }
    var numbers = Array(min...max)
    var randoms = [Int]()
    for _ in 1...count {
        let index = Int(arc4random_uniform(UInt32(numbers.count)))
        let value = numbers[index]
        randoms.append(value)
        numbers.remove(at: index)
    }
    return randoms
}

var randomArray = uniqueRandomArray(count: 10, min: 1, max: 10)

Get Random Element From Array

For getting random item from array you need just generate random index and get item with this index.
let array = ["Star", "Wars", "Empire", "Strikes", "Back"]
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomIndex])

Generate Random UIColor

For generating random UIColor lets explore one of initializer that available for class UIColor.
UIColor(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
As we can see there are float components, so we can randomly generate integer numbers and convert these values to CGFloat.
let redComponent = CGFloat(arc4random_uniform(255)) / 255.0
let greenComponent = CGFloat(arc4random_uniform(255)) / 255.0
let blueComponent = CGFloat(arc4random_uniform(255)) / 255.0

let randomColor = UIColor(red: redComponent, green: greenComponent,
                          blue: blueComponent, alpha: 1.0)
Function for creating random color
func randomColor(randomAlpha: Bool = false) -> UIColor {
    let redComponent = CGFloat(arc4random_uniform(255)) / 255.0
    let greenComponent = CGFloat(arc4random_uniform(255)) / 255.0
    let blueComponent = CGFloat(arc4random_uniform(255)) / 255.0
    let alphaComponent = randomAlpha ? CGFloat(arc4random_uniform(255)) / 255.0 : 1
    let randomColor = UIColor(red: redComponent, green: greenComponent,
                              blue: blueComponent, alpha: alphaComponent)
    return randomColor
}

let randomColor2 = randomColor(randomAlpha: false)
Making an extension for UIColor
extension UIColor {
    class func random(randomAlpha: Bool = false) -> UIColor {
        let redComponent = CGFloat(arc4random_uniform(255)) / 255.0
        let greenComponent = CGFloat(arc4random_uniform(255)) / 255.0
        let blueComponent = CGFloat(arc4random_uniform(255)) / 255.0
        let alphaComponent = randomAlpha ? CGFloat(arc4random_uniform(255)) / 255.0 : 1
        let randomColor = UIColor(red: redComponent, green: greenComponent,
                                  blue: blueComponent, alpha: alphaComponent)
        return randomColor
    }
}

UIColor.random()

Source Code

Source code for this post could be found here on GitHub

12 comments:

  1. Really nice article. its really helpful me. Very interesting and good post thanks for sharing such a good blog.
    -Web Development Services

    ReplyDelete
  2. There are many articles circulating on internet that exaggerate about Custom Designed Websites. But your article is an exception that made me understand it without any difficulty.

    ReplyDelete
  3. Thank you very much for bringing this to my attention. Your blog is chock-full of useful information. I'd have no idea unless I read that. I'll return for more excellent content. Best wishes and best of success to you. Best Custom Websites

    ReplyDelete
  4. Great content. I was looking for this kind of content. It saved my time to search further.
    You must provide such type of content constantly. I appreciate your willingness to provide readers with a good article.
    Custom Design Websites

    ReplyDelete
  5. Thank you for writing this quality informational content.Your writing technique is impressive and enjoyable to read. I'll come back for more fantastic material.
    Best wishes, and good luck.
    Custom Build Website

    ReplyDelete
  6. Thanks to your article now I understand or learn many new things which are very difficult to understand the way you describe this topic is very easy to understand. Web Design USA

    ReplyDelete
  7. Thank you for writing this quality informational content. Your writing technique is good and enjoyable to read. I'll come back for more fantastic material.
    Best wishes, and good luck.
    Mobile Performance Meter Hack

    ReplyDelete
  8. Great share!One of the best blogs I have Ever Seen. Keep going!
    SEO Service NYC

    ReplyDelete
  9. This is one of the nicest blogs I've ever seen, and it's really

    pleasant. This is a very valuable blog for me, and one of the most

    helpful blogs I've ever seen.
    Search Engine Marketing Services

    ReplyDelete
  10. One of the best blogs I have ever seen. Keep going!
    Paul allen | CBD Crystal Isolate Wholesale

    ReplyDelete
  11. Please keep writing this type of article posts; I like it.
    Amber Cooper | Pure CBD Disposable

    ReplyDelete