BLACK FRIDAY SALE: Save big on all my Swift books and bundles! >>

Checkpoint 9: can someone help me

Forums > 100 Days of SwiftUI

I kind of understand hoe to make the logic but i don't know how to do it in a single line

   

I haven't looked at the particular challenge in question. So my comment here is in a general context and not about this particular quesiton (which I'll also go look at when time permits):

As someone who's been doing this for over 3 decades, there's a universal truth about "clever" solutions: single line "solutions" to complex problems usually end up being more trouble than they're worth in terms of how long it takes to figure it out, code readability and maintainability, friendliness to the next developer (which might be you in a year after you've forgotten all that cleverness), and changing specs or functionalities.

There. That's my cranky old guy warning. :) Now I'll go look up this particular thing and see if I can help :)

   

Try breaking it down one step at a time. First, write out your code using multiple lines. Then see what parts you can eliminate and what parts you can combine. Post what you have so far, if you're stuck.

   

Hacking with Swift is sponsored by RevenueCat

SPONSORED In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.

Learn more

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

Follow Vince's advice and break down the problem one step at a time.

Don't peek! But here's a previously posted solution:

Checkpoint 9 Help

   

I used a closure since it's supposed to be one line. Looks like the code works but not sure if my reasoning in the comments is correct.

// Chained the optional array of Integer "[Int]?" to  "randomElement()" which by default is also an optional in case the array is empty, then added nil coalescing to run the random number generator "Int.random(in:1...100)" in case of nil or absent value.

let randomIntReturns = {(array: [Int]?) -> Int in array? .randomElement() ?? Int.random(in: 1...100)}

//testing function
randomIntReturns([])
randomIntReturns([3,4,12,68,1233])

   

Phew! Inspired to post for the first time after completing this checkpoint. For the first time in the first fortnight, I had to watch every video again, after I'd made a first attempt at the checkpoint, before I got to my solution.

Exactly as Vince said, breaking it down step by step helped immeasurably.

First, I thought I'd create optional arrays to test the conditions of the checkpoint:

var myArray: [Int]? = [Int]()          // creates an empty optional array
var myRealArray: [Int]? = [1, 2, 3, 4] // creates an filled optional array
var doesNtExist: [Int]? = nil          // this array does not exist - it is not 'empty'
                                       // myArray and myRealArray COULD be non-optional if i wanted

Then I thought I'd practice using them to check one of the conditions - does the optional exist. First I wrote an if let for each array individually, then a function containing an if let into which an optional array could be passed:

if let myArray = myArray {             // all three arrays are optional, this one is empty
    print("Optional array exists")
    print(myArray)
}

if let myRealArray = myRealArray {     // 'if let' only works on optionals and _UNWRAPS_ them into a
    print("Optional array exists")     // temporary var or constant, traditionally of the same name
    print(myRealArray)                 // this array _has_ values which are printed
}

if let doesNtExist = doesNtExist {     // this optional array has NO value and does not
    print("Optional array exists")     // satisfy the 'if' because of that fact
    print(doesNtExist)
} else {                               // if let runs the code if the optional exists
    print("That array does not exist!")// but you can have an else statement too to do something
}

// convert our 'ifs' to a function

func doesArrayExist(name: [Int]?) {    // has to accept optional arrays; if we tell Swift we are
    if let name = name {               // passing a non-optional array, that's what it expects
        print("If let says: Optional array exists") // and so 'if let' would make no sense
        print(name)
    } else {
        print("If let says: That optional array does not exist!")
    }
}

doesArrayExist(name: myArray)
doesArrayExist(name: myRealArray)
doesArrayExist(name: doesNtExist)

I took my ages to get to that function!

But I thought it would be easy enough to reverse the order of the function with a guard let:

func doesArrayExistGuarded(name: [Int]?) { // guard let allows code to stop running as soon as a
    guard let name = name else {           // check has not been satisfied
        print("Guard says: That optional arrays does not exist")
        return
    }
    print("Guard says: Optional array exists")
    print(name)
}

doesArrayExistGuarded(name: myArray)
doesArrayExistGuarded(name: myRealArray)
doesArrayExistGuarded(name: doesNtExist)

I was fairly sure the second condition would be easy to implement with .randomElement() and so combined that with nil coalescing. I used my three test optional arrays with three different returns, for reasons that might make sense only to me! (it felt right) The optional array with values should return one of the values from that array and so the nil coalescing will never be needed. Again, for reasons only known to me, I decided to test all this in a while loop to run it three times. Maybe I'm Irish ("To be sure! To be sure! To be sure!")

var i = 0
while i < 2 {
    let randomNo1 = myRealArray?.randomElement() ?? Int.random(in: 5...100)  // passes - array exists and has values
    let randomNo2 = myArray?.randomElement() ?? Int.random(in: 5...100)      // fails - random element returns 'nil'
    let randomNo3 = doesNtExist?.randomElement() ?? Int.random(in: 101...200)// fails - optional array does not exist so 'nil' is returned
    print("\(randomNo1) & \(randomNo2) & \(randomNo3)")
    i += 1
}

When that worked I thought I could nail the one-line function:

func checkpoint(arr: [Int]?) -> Int { arr?.randomElement() ?? Int.random(in: 1...100) }

Then I thought I could be clever and pass my three arrays into the function in a loop. This caused ten minutes of head scratching until I realised the for loop was being passed an array containing optional arrays of integers. After I had said that out loud, the notation "[[Int]?]" formed in my brain, and the problem was solved:

// an arrary of optional integer arrays
let arrayOfArrays: [[Int]?] = [myArray, myRealArray, doesNtExist]

// loop through the array, calling the function
for i in arrayOfArrays {
    print("generating random number: ")
    print(checkpoint(arr: i))
}

I loved this challenge, even though it took me three times longer than any other so far!

   

This one hurt my brain a bit, but I think I got there.

func randomFromArray(theArray: [Int]?) -> Int {
    return theArray?.randomElement() ?? Int.random(in: 1...100)
}

   

Nick did a nice job whilst sustaining a wee brain bruise:

This one hurt my brain a bit, but I think I got there.

// Nick's code
func randomFromArray(theArray: [Int]?) -> Int {
    return theArray?.randomElement() ?? Int.random(in: 1...100)
}

Two thoughts for you as you progress on your journey.
First, think about how your code reads. Say it out loud as if you're reading a sentence.

Does this sound like a natural sentence?

let someArray = [42, 10, 87, -33, 666]  // just some random integers
let someRandomInteger = randomFromArray( theArray: someArray)
// READ like a sentence: 
// Let some random integer equal random from array theArray someArray.

Natural language coding

Consider changing the function name and its parameters to help your code read like a natural sentence.

// Minor revisions
// Changed the function name and parameter.        
// Does this help make reading code easier?
func randomInteger(from inputArray: [Int]?) -> Int {
    return inputArray?.randomElement() ?? Int.random(in: 1...100)
}

let someArray = [42, 10, 87, -33, 666]  // just some random integers

// Read this as a sentence
let someRandomInteger = randomInteger(from: someArray)  // Is this more natural?
// READ like a sentence: 
// Let some random integer equal random Integer from some array.

There are many variations! My answer is often not the correct one. Pick function names and parameters that help your team read your code effortlessly. Your intentions should be very clear.

Second hint: because your function only contains one line of code and your function must return an Integer, the Swift compiler will infer that your one liner MUST calculate an integer. Thus, the return keyword is NOT required. Cool!

// Minor revisions
// Removed the return keyword
func randomInteger(from inputArray: [Int]?) -> Int {
   inputArray?.randomElement() ?? Int.random(in: 1...100) // return keyword not required!
}

Cool stuff! Keep posting questions and your progress.

2      

Here is my take...

func randomFromArray(from theArray: [Int]?) -> Int { theArray?.randomElement() ?? Int.random(in: 1...100) }

1      

@tomn  

This one was a head-scratcher and stare-at-monitor kind of challenge.

func randNum(from array: [Int]?) -> Int { array?.randomElement() ?? Int.random(in: 1...100) }
print(randNum(from: [101,102,103]))

   

Hacking with Swift is sponsored by RevenueCat

SPONSORED In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.

Learn more

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.