WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

Checkpoint 9: Optionals with a Twist

Forums > 100 Days of SwiftUI

  • Spoiler below. Please try on your own before looking at my hack.

In Checkpoint 9, Paul challenges us to write a function that accepts an optional array of integers and returns a random value from the array. However, if the function's parameter is nil, Paul wants us to use a default array of values from 1 through 100.

The twist? Do this in one line of code.

First I thought of how would you name such a function. I toyed with a few names and settled on "pickOne". The parameter has two names, one for external use, the other for internal use. What function name did you pick? Add your comments below and share your thoughts.

func pickOne(fromThese someIntegers: [Int]? ) -> Int  { // challenge code goes here }

This allows a user to write:

let randomValue = pickOne(fromThese: [ 142, 242, 342, 442, 524] )  // user provided array of integers

Next, regardless of what is provided, return a random value between 1 and 100.

func pickOne(fromThese someIntegers: [Int]? ) -> Int  {
    return Array(1...100).randomElement()!  // force unwrap
}

The odd thing here is even though I'm providing a valid integer array, the randomElement() method returns an optional. So I need to force unwrap it. I'm not afraid of this crashing, because indeed I am providing a bona fide array of Ints.

Next, figure out if the user provided a valid array, or nil.

    return someIntegers?.randomElement()

This is an optional chain. And either of these can return nil. First, the array might not even exist, thus returning nil. Second, if the array exists, it might be an empty array, so randomElement() will return nil as well. In this case, the nil coalescing operator comes to the rescue. If the first part returns nil, then provide a value from the second part of the nil coalescing operation. Also, because there is only one line that creates an Int value, Swift considers this the return value. No need to use the return keyword.

func pickOne(fromThese someIntegers: [Int]? ) -> Int  {
    someIntegers?.randomElement() ?? Array(1...100).randomElement()!  // force unwrap
}

I think this qualifies as a one line function.

1      

The odd thing here is even though I'm providing a valid integer array, the randomElement() method returns an optional.

Because what should it return if you call randomElement() on an empty array? 😜

1      

This is what I came up with

func randomGen (of array: [Int]?) -> Int {
    array?.randomElement() ?? Int.random(in: 1...100)

}

randomGen(of: [-1,-4,-8,-9,-102])
randomGen(of: [-1,-4,-8,-9,-102])
randomGen(of:[])
randomGen(of: nil)

1      

@Feras-Eng

Elegant solution. Why should I create an array, then pick a random element from it. (Plus the overhead of unwrapping it!) Your solution of just picking a random number in a closed range is brilliant! Well done.

I know these checkpoints are supposed to help us understand concepts, but as your example shows, it also helps us think through many ways to accomplish a task. Your solution is much cleaner.

Likewise, I offer this observation to you. Your function's goal is to select a random number from within an array. Does your method's name and parameter make this clear?

randomGen(of: )      // Is your function's intention clear?

2      

hello every one i'm new here i have question to @Obelix about his soluton for the Checkpoint 9 is it necessarily to do the "!" after Array(1...100).randomElement()

   

Rami asks an important question!

Checkpoint 9: Is it necessarily to do add the "!" after Array(1...100).randomElement()

This is a great observation. And this is an important lesson about Optionals.

The answer is "YES" you must add the "!" after the code Array(1...100).randomElement()

See @rooster's answer above. But here's a bit more explanation:

The reason is important for you to understand. It has to do with Optionals.

You and I both see that I'm creating an array with numbers from 1 to 100, we can conclude this array IS NOT EMPTY. Therefore, it is safe to assume that I can ask Swift to select a random element from the array and it will return one of the elements.

However, the randomElement() method cannot assume that it will always be given an array with actual values. Consequently, it will try its best to pull out a random element for you, but if you provided an array that was EMPTY, it cannot give you a random element.

By definition, the randomElement() method returns an Optional<Element>. So if you give the randomElement() an empty array, it will return nil, indicating that it could not provide you with an element of your array. However, we KNOW this array has values, so we can force unwrap the returned element using the bang character (!).

At this point in your learning career, you'll want to start to get familiar with Apple's Swift Documentation. Get comfortable finding documentation about methods, reading the requirements, and learing about the return types.

Here's the documentation for Array's randomElement() method.

See -> randomElement()

   

Hacking with Swift is sponsored by Fernando Olivares

SPONSORED Fernando's book will guide you in fixing bugs in three real, open-source, downloadable apps from the App Store. Learn applied programming fundamentals by refactoring real code from published apps. Hacking with Swift readers get a $10 discount!

Read the book

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.