Broze / Gold Challenges

I found this chapter a little tricky, simply because I’m a little newer to functional programming. Reducing the closures from long, expressive syntax to just a few characters and have it essentially do the same thing is both beautiful and frightening at the same time, so I made sure to go through this a few times just to make sure I understood it.

Anyway, on to my solutions:

Bronze Challenge 1:

This one I found a little too straightforward–instead of assigning the sort to another variable, you can just sort it.

Note: In the documentation, sort() is said to sort an array in-place, however, when using that function I get a compile error saying sort() is replaced with sorted(). Not sure why, but the documentation seems to be a little behind the compiler.

volunteerCounts.sorted { $0 < $1 }
print(volunteerCounts)

Bronze Challenge 2:

Again, kinda straightforward. Instead of sorted(by:), you just leave off the parameter.

volunteerCounts.sorted()
print(volunteerCounts)

Gold Challenge

This one I wanted to follow through similar to how we reduced the sorted(by:) function at the beginning of the chapter. To begin with, we have this:

let totalProjection = projectedPopulations.reduce(0, {
    (accumulatedProjection: Int, precinctProjection: Int) -> Int in
    return accumulatedProjection + precinctProjection
})

Side note: I don’t like reduce(0){} simply because, coming from other languages, this seems a little disjointed. If they are both in the method parameter body, it makes it a little more obvious what’s going on and what applies to what. Just a preference though.

Simplify that a bit by trimming the type information (which can be inferred):

let totalProjection = projectedPopulations.reduce(0, {
    accumulatedProjection, precinctProjection in
    accumulatedProjection + precinctProjection
})

But again, we can get that to be way more concise. My final solution:

let totalProjection = projectedPopulations.reduce(0, { $0 + $1 })

I encourage everyone to update this forum with their own solutions as they’re going along. Looking forward to providing solutions to other chapters!

1 Like

@macintacos, regarding Bronze Challenge 1 & 2

I ran into the same compile time error. However, your solution did not work for me. The sorted() method did not sort the array in place.

However, when I added a new “var” the compiler allowed me to use the sort() method. The earlier compiler error message, in my opinion, should have been “sort not allowed on let/constants”.

var volunteerCounts2 = volunteerCounts

volunteerCounts2.sort { $0 < $1 }
print(volunteerCounts2)

Ah, that makes sense. Thanks for clearing that distinction up for me. Maybe I was just confused with the outputs I was getting to think that I had the solution.

Here’s my understanding (very basic…). I’m writing it out, in case it’s wrong and somebody can correct it for me…

Sorting in place requires array.sort() – and it needs the array to be mutable (var, not let). By default it sorts in ascending order.

volunteerCounts.sort()   // volunteerCounts must be mutable (var, not let)

Array.sorted returns a sorted copy of the original array and then sorts the copy, so it can be used with immutable arrays. It’s also in ascending order by default.

let volunteersSorted = volunteerCounts.sorted() // volunteerCounts can be immutable

To change to descending in both cases, use (by: >).

The difference in naming is important and is common throughout Swift 3: sort (a verb) denotes the action is on the original array, sorted (a noun) denotes a new object is returned.

Hope that’s right… please tell me if it isn’t!

1 Like

For the Gold Challenge:

let TotalProjection = projectedPopulations.reduce(0) { $0 + $1 }

This works, but I managed to get to it more by luck than judgement… I adapted the concept from the previous discussion on sorted{by: $0 < $1) and played around with it till it worked.

Trying to understand why it works, with the help of the documentation. I think it’s because reduce(::) expects two inputs: a starting value and a closure which is applied to each element of the array in turn.

Here (0) is the starting value, which becomes the initial value of $0 (the accumulating value) which is added to $1 (the first element). The resulting total is taken forward to the next iteration as the new $0 accumulating value and is added to the next element ($1) and so on till the end of array.

Please forgive the no doubt simplistic interpretation. I’m trying to understand it by explaining it, on the grounds that if I can’t describe the process, I don’t really understand it, so any corrections / amplifications are very welcome…

New at all this too…
I think it’s helpful when you add the prior lines of code since as others have noted the variable types sometimes need to be changes. I came up with these.

Bronze:
var volunteerCounts = [1,3,40,32,2,53,77,13] //changes let to var
volunteerCounts.sort(by: <)
print(volunteerCounts)

Gold:
let precinctPopulations = [1244, 2021, 2157]
let projectedPopulations = precinctPopulations.map {$0 * 2}
let totalProjection = projectedPopulations.reduce(0) {$0 + $1}
totalProjection

What was your approach for searching through the documentation for the 2nd bronze challenge? I’m having trouble understanding how to effectively search through the documentation.

I like to start a search for more info in Xcode by, in the code editing window, performing an option-click on the term that I am interested in. This produces, for a method like sorted(by:), a pop-up window of a technical description of the method, some code examples of its use and, at the bottom of the window, a link for “More” info. In this case the link is entitled "Method Reference. " Clicking on the link brings up a Documentation and API Reference browser window in Xcode for the instance method sorted(by:).

This is even shorter…

let totalProjection = projectedPopulations.reduce(0, + )

1 Like

Bronze:

Well, I’m not overly sure what the authors are after on the Bronze challenge #1. Here’s what I have

//Version 1: Sort the array and store it back into its same array name
var volunteerCounts1 = [1, 3, 40, 32, 2, 53, 77, 13]
volunteerCounts1 = volunteerCounts1.sorted { $0 < $1 }
print(volunteerCounts1)

//Version 2:  Just use the sorted array without storing it back in a variable
var volunteerCounts2 = [1, 3, 40, 32, 2, 53, 77, 13]
print(volunteerCounts2.sorted { $0 < $1 })

//Version 3:  Another way of doing it.
var volunteerCounts3 = [1, 3, 40, 32, 2, 53, 77, 13]
let newCount = volunteerCounts3.sorted {
    (count1: Int, count2: Int) -> Bool in
   count1 < count2
}
print(newCount)

Bronze Challenge #2 seems to just be this:

volunteerCounts3.sorted()

So, you can do things like:

print(volunteerCounts3.sorted())

and it prints a version of the array sorted without altering the original array.

On the Gold challenge, you apparently can get away with doing this:

print(precinctPopulations.reduce(0) {$0 + $1})

And frankly, I would never write a line of code like that. I’d much rather write a simple function to make this much more readable.

I have to say, this chapter was the first one that really threw me. I had to read it three or four times, and I still have trouble with all of the “functions as argument” stuff. It just makes the code unreadable and unnecessarily complex in my eyes. I get it in the end, but I’m just not going to write code like that.

1 Like

For the Gold Challenge:

let totalProjection = projectedPopulations.reduce(0, { $0 + $1 })

How does the function know which two values to add together? I know it’s adding the first and second indices but how and when was accumulatedProjection and precinctProjection stored in those indices?

1 Like

accumulatedProjection and precinctProjection aren’t being stored back into projectedPopulations, and reduce isn’t just adding the first two indices together. reduce iterates over the entire array, executing the closure once for each array element. The first argument passed to the closure is set to the value returned by the closure operating on the previous array element, and the second argument is set to the current array element. Since this closure doesn’t provide any names for the arguments passed to it, they default to $0 and $1.

Lets walk through it. projectedPopulations contains the values [2488, 4042, 4314]. When reduce operates on the first array element, $0 is 0 (since this is the first time reduce is executing the closure, $0 gets set to the first argument passed in to reduce, which in this case is zero) and $1 is the first array value, 2488. The closure adds them together & returns a value of 2488.

Then reduce moves on to the second array element and executes the closure again. This time $0 is the result from the previous closure execution (2488) and $1 is the second array value (4042). The closure adds them together & returns a result of 6530.

Then reduce moves on to the third array element and executes the closure for the final time. $0 is the result of the previous closure execution (6530) and $1 is the third array value (4314). The closure adds them together and returns a result of 10844. Since we’re at the end of the array, this is the value returned by reduce.

1 Like

Thanks this helps a lot. I had already figured it out though

// Bronze Challenge 1
var volunteerCounts1: [Int] =
volunteerCounts1 = volunteerCounts.sorted()
print(volunteerCounts1)
print(volunteerCounts1.sorted())

// Bronze Challenge 2
let bronzeChallenge2 = volunteerCounts.sorted(by: <)
bronzeChallenge2

//Or just
print(volunteerCounts.sorted())

// Golden Challenge 1
let goldenChallenge1 = projectedPopulations.reduce(0,{ $0 + $1})
goldenChallenge1