UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Checkpoint 5

Forums > Swift

Link to Checkpoint 5

Gentle People,

For Checkpoint 5, I imagined this:

  1. A function that takes any array of numbers you think are lucky, or unlucky, or favourite, etc.
  2. The function applies sorted(), filter(), & map() to extract the true 'winning' numbers.
  3. It directly prints out these winning numbers in a neat string format, plain as day, for you to see.

No muss, no fuss. Just give the function your collection of numbers, and the function will tell you which of them are winning numbers, if any.

Here's what I've got:

let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]

func winningNumberFinder(_ array: [Int]) {
    var winningNumbers = array.sorted {$0 < $1}.filter {$0 % 2 != 0}.map{String($0) + " is a Winning Number!"}
    for i in winningNumbers {
        print(i)
    }
    if winningNumbers.isEmpty {
        print("None of your numbers will win.")
    }
}

winningNumberFinder(luckyNumbers)

let normalNumbers = [6, 76, 9, 8, 16, 27, 33, 98, 59, 12]
winningNumberFinder(normalNumbers)
let unluckyNumbers = [0, 4, 8, 22, 48]
winningNumberFinder(unluckyNumbers)

My questions are:

  1. I seem to be getting the answer as expect... but have I cleared Checkpoint 5, following Paul's core instructions? If not, why?
  2. Could this same functionality be achieved without using any variables, without destroying the original input, and without a 'for...in' loop?
  3. In his video, Paul specifically said "must use (isMultiple(of: _ ))" to filter. Is there a reason why I mustn't use the remainder operator? How would my code have changed if I did exactly what Paul said?
  4. Have I demonstrated a good/expected use of 'Closures' for Checkpoint 5?
  5. Have I chanied the functions as expected, and is this what Paul meant when he said, 'chain the functions'? Is there no other way to chain a function?
  6. Paul said, "use luckyNumbers.one, luckyNumbers.two, etc" to chain the functions. What did he mean by this?
  7. I know my code can be better -- it could be shorter, less clustered, etc. Could you please show me how?

I sincerely apologise if I've asked too many questions and for taking more of your time -- I just really want to understand this, foundationally. I'm looking forward to any and all your amazing replies.

Thank you very much :)

PS: I know I am adding slightly more functionality to this code than the scope of Checkpoint 5. My objective is to first do exactly what Paul said within the confinements he set, and then build my small bit of 'extra' on top of it. In other words, I definitely want my function to work this way for the 'end user', provided I completely understand where Paul was coming from with his rules for Checkpoint 5, and what he wanted of us as coders.

2      

I seem to be getting the answer as expect... but have I cleared Checkpoint 5, following Paul's core instructions? If not, why?

Looks good to me. I'd probably swap the sorted and filter operations so that you are sorting fewer items, but that's no biggie.

Could this same functionality be achieved without using any variables, without destroying the original input, and without a 'for...in' loop?

Not sure what you mean by "without destroying the original input". It's not destroyed, it's still there.

There's no good way to do it without using any variables if you want the "None of your numbers will win" message, but otherwise you could do this:

func winningNumberFinder(_ array: [Int]) {
    array
        .filter { $0.isMultiple(of: 2) }
        .sorted(by: <)
        .map { "\($0) is a winning number" }
        .forEach { print($0) }
}

And, really, in this case the map isn't even necessary, as you could just do:

.forEach { print("\($0) is a winning number") }

In his video, Paul specifically said "must use (isMultiple(of: _ ))" to filter. Is there a reason why I mustn't use the remainder operator?

Clarity and ease of reading. Also, % doesn't function as expected in certain cases involving negative numbers.

To quote from the Swift forum thread where the pitch for isMultiple(of:) was accepted:

It is substantially more fluent than its standard implementation of value % divisor == 0. Divisibility testing is the operation people actually want; the % operator is just the way they have to achieve it. % is rarely used outside of this idiom, and many programmers have no other reason to know it. It is not a familiar operator for new programmers especially: they will usually be comfortable with remainders in the context of division, but they aren't used to thinking about computing a remainder as a separate operation, and they certainly don't recognize % as a symbol for it. Even experienced programmers often mentally "pattern-match" this sort of expression to recognize it as a divisibility test instead of thinking through the arithmetic of it.

Encouraging the use of isMultiple(of:) (and !isMultiple(of:)) serves to counter bugs around negative remainders.

Next question...

Have I demonstrated a good/expected use of 'Closures' for Checkpoint 5?

Sure.

Have I chanied the functions as expected, and is this what Paul meant when he said, 'chain the functions'? Is there no other way to chain a function?

You're good. Although as I mentioned above I'd probably swap the sorted and filter functions.

Paul said, "use luckyNumbers.one, luckyNumbers.two, etc" to chain the functions. What did he mean by this?

When Paul said to use luckyNumbers.first { }.second { }, he also mentioned plugging in the actual function names instead of first and second.

I know my code can be better -- it could be shorter, less clustered, etc. Could you please show me how?

Your code looks okay. Changes I'd suggest:

  1. winningNumbers should be a let instead of a var since you don't need it to change.
  2. Swap sorted and filter.
  3. You don't need to specify the closure body for sorted, you can just give it the < function.
  4. Use isMultiple(of:).
  5. Use string interpolation for generating the String in your map closure instead of concatenating two Strings.
  6. Drop your chained functions onto separate line to make them easier to read.
  7. Use a guard statement to catch an empty winningNumbers array.
func winningNumberFinder(_ array: [Int]) {
    let winningNumbers = array.filter { $0.isMultiple(of: 2) }
        .sorted(by: <)
        .map{ "\($0) is a Winning Number!" }

    guard !winningNumbers.isEmpty else {
        print("None of your numbers will win.")
        return
    }

    for i in winningNumbers {
        print(i)
    }
}

2      

Thank you for your response :)

Just one follow up:

When Paul said to use luckyNumbers.first { }.second { }, he also mentioned plugging in the actual function names instead of first and second.

Could you please show me how exactly he meant for us to do this?

2      

Exactly like you did it here:

var winningNumbers = array.sorted {$0 < $1}.filter {$0 % 2 != 0}.map{String($0) + " is a Winning Number!"}

In this case, your first function is sorted, your second function is filter, etc.

3      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.