Unwrapping optional inside of closure using reduce - swift

I have a quick question that is confusing me a little bit. I made a simple average function that takes an array of optional Ints. I check to make sure the array does not contain a nil value but when I use reduce I have to force unwrap one of the two elements in the closure. Why is it that I only force unwrap the second one (in my case $1!)
func average2(array: [Int?]) -> Double? {
let N = Double(array.count)
guard N > 0 && !array.contains({$0 == nil}) else {
return nil
}
let sum = Double(array.reduce(0) {$0+$1!})
let average = sum / N
return average
}
I know it is simple but I would like to understand it properly.

The first parameter of reduce is the sum, which is 0 in the beginning. The second one is the current element of your array which is an optional Int and therefore has to be unwrapped.
Your invocation of reduce does this:
var sum = 0 // Your starting value (an Int)
for elem in array {
sum = sum + elem! // This is the $0 + $1!
}
EDIT: I couldn't get a more functional approach than this to work:
func average(array: [Int?]) -> Double? {
guard !array.isEmpty else { return nil }
let nonNilArray = array.flatMap{ $0 }
guard nonNilArray.count == array.count else { return nil }
return Double(nonNilArray.reduce(0, combine: +)) / Double(nonNilArray.count)
}
You can also discard the second guard if you want something like average([1, 2, nil]) to return 1.5 instead of nil

Related

"Array index is out of range:" when get a range from an array

I have an array anArray and I want to create a sub array by specifying a range range, like:
var range: Range<Int>
guard let slice = anArray[range] else {
return nil
}
I run into a problem where the code throws an "Array index is out of range:" exception.
var range: Range<Int>
guard range.upperBound > anArray.count - 1 else {
return nil
}
guard let slice = anArray[range] else {
return nil
}
But I see get the Array out of range exception. Can you please tell me what did I miss?
Your operator is backwards, the guard should be ensuring
guard range.upperBound <= anArray.count - 1 else { ...
not >
(The guard will skip the else block if its condition is true - it isn't an if, it's an else).
Besides the fact that you were using the wrong operator beware that not all collections starts at zero and not all collections have all elements up to its index before the endIndex. Thats the case of the result of your subscription which returns an ArraySlice. You should always check the collection indices, not its count. Resuming you should check if your range fits within the collection indices. Check this post. Note that RandomAccessCollection's subscript does NOT return an optional, it would crash if you pass an invalid range.
guard range.clamped(to: anArray.indices) == range else {
return nil
}
let slice = anArray[range]

Finding the largest number in a [String: [Int]] Swift dictionary

I am new in Swift.
I have an error with this code and I can't find any answer on this site.
I print largest number but I want to print largest number's kind.
let interestingNumbers = [
"Prime": [2,3,5,7,11,13],
"Fibonacci": [1,1,2,3,5,8,13],
"Square": [1,4,9,16,25,36]
]
var largestNumber = 0
for (kind, numbers) in interestingNumbers {
for x in numbers {
for y in kind {
if x > largestNumber {
largestNumber = x
}
}
}
}
print("the largest number is = \(largestNumber)")
Try this instead:
var largestNumber = 0
var largestNumberKind: String!
for (kind, numbers) in interestingNumbers {
for x in numbers {
if x > largestNumber {
largestNumber = x
largertNumberKind = kind
}
}
}
print("the largest number is = \(largestNumber)")
print("the largest number kind is = \(largestNumberKind)")
Regarding your original code:
you were only keeping track of the largest number, losing the kind info you wanted. The largestNumberKind variable I added does just that.
looping over the kind: String didn't make any sense (the for y in kind line). Your outside loop already iterates a key at a time, so such inner loop is pointless.
There is nothing wrong with Paulo's approach (with some minor corrections; see comments there), but this is a reasonable problem to explore more functional approaches that don't require looping and mutation.
For example, we can just flatten each kind to its maximum element (or Int.min if it's empty), then take the kind with the highest max:
interestingNumbers
.map { (kind: $0, maxValue: $1.max() ?? .min) } // Map each kind to its max value
.max { $0.maxValue < $1.maxValue }? // Find the kind with the max value
.kind // Return the kind
This does create a slight edge condition that I don't love. If you evaluate the following:
let interestingNumbers = [
"ImaginaryReals": [],
"Smallest": [Int.min],
]
It's not well defined here which will be returned. Clearly the correct answer is "Smallest," but it's kind of order-dependent. With a little more thought (and code) we can fix this. The problem is that we are taking a little shortcut by treating an empty list as having an Int.min maximum (this also prevents our system from working for things like Float, so that's sad). So let's fix that. Let's be precise. The max of an empty list is nil. We want to drop those elements.
We can use a modified version of mapValues (which is coming in Swift 4 I believe). We'll make flatMapValues:
extension Dictionary {
func flatMapValues<T>(_ transform: (Value) throws -> T?) rethrows -> [Key: T] {
var result: [Key: T] = [:]
for (key, value) in self {
if let newValue = try transform(value) {
result[key] = newValue
}
}
return result
}
}
And with that, we can be totally precise, even with empty lists in the mix:
interestingNumbers
.flatMapValues { $0.max() }
.max { $0.1 < $1.1 }?
.key
Again, nothing wrong with Paulo's approach if you find it clear, but there are other ways of thinking about the problem.
BTW, the equivalent version that iterates would look like this:
var largestNumber: Int? = nil
var largestNumberKind: String? = nil
for (kind, numbers) in interestingNumbers {
for x in numbers {
if largestNumber == nil || largestNumber! < x {
largestNumber = x
largestNumberKind = kind
}
}
}

Is it possible to cut short evaluation of a higher-level function?

I am looking for a way to stop a higher-level function after evaluating part of its input sequence.
Consider a situation when you look for the first index in a sequence that satisfies a certain condition. For example, let's say we are looking for the first position in an array a of Ints where the sum of two consecutive values is above 100.
You can do it with a loop, like this:
func firstAbove100(a:[Int]) -> Int? {
if a.count < 2 {
return nil
}
for i in 0..<a.count-1 {
if a[i]+a[i+1] > 100 {
return i
}
}
return nil
}
The looping stops as soon as the position of interest is discovered.
We can rewrite this code using reduce as follows:
func firstAbove100(a:[Int]) -> Int? {
if a.count < 2 {
return nil
}
return (0..<a.count-1).reduce(nil) { prev, i in
prev ?? (a[i]+a[i+1] > 100 ? i : nil)
}
}
However, the disadvantage of this approach is that reduce goes all the way up to a.count-2 even if it finds a match at the very first index. The result is going to be the same, but it would be nice to cut the unnecessary work.
Is there a way to make reduce stop trying further matches, or perhaps a different function that lets you stop after finding the first match?
As already said, reduce is specifically designed in order to evaluate an entire sequence and therefore not designed to short-circuit. Using it in this way to find an the index of an element that meets a given predicate is best done with indexOf as #Casey says.
Also as of Swift 3, there is now a first(where:) function on Sequence that allows you to find the first element that satisfies a given predicate. This could be an even more suitable alternative than indexOf, as it returns the element instead of the index (although in your particular example these are the same).
You could write your example like this:
func firstAbove100(_ a:[Int]) -> Int? {
guard a.count > 1 else {return nil}
return (0..<a.count-1).first { i in
a[i]+a[i+1] > 100
}
}
However if you want a more general high level function that will iterate through a sequence and break out if it finds a non-nil result of a given predicate – you could always write your own find function:
extension SequenceType {
func find<T>(#noescape predicate: (Self.Generator.Element) throws -> T?) rethrows -> T? {
for element in self {
if let c = try predicate(element) {return c}
}
return nil
}
}
You could now write your firstAbove100 function like this:
func firstAbove100(a:[Int]) -> Int? {
if a.count < 2 {
return nil
}
return (0..<a.count-1).find { i in
a[i]+a[i+1] > 100 ? i : nil
}
}
and it will now short-circuit when it finds a pair of elements that add to above 100.
Or let's say instead of returning the index of the first pair of elements in your array that add to greater than 100, you now want to return the sum of the elements. You could now write it like this:
func sumOfFirstAbove100(a:[Int]) -> Int? {
guard a.count > 1 else {return nil}
return (0..<a.count-1).find { i in
let sum = a[i]+a[i+1]
return sum > 100 ? sum : nil
}
}
let a = [10, 20, 30, 40, 50, 60, 70, 80, 90]
print(sumOfFirstAbove100(a)) // prints: Optional(110)
The find function will iterate through the array, applying the predicate to each element (in this case the indices of your array). If the predicate returns nil, then it will carry on iterating. If the predicate returns non-nil, then it will return that result and stop iterating.
indexOf will stop after it finds the first match so you might rewrite firstAbove100 to something like this:
func firstAbove100(a:[Int]) -> Int? {
return a.count > 1 ? (a.startIndex..<a.endIndex-1).indexOf({ a[$0] + a[$0 + 1] > 100 }) : nil
}

Use guard-let to modify possibly nil expression before assigning variable

I wish to use guard-let to assign a variable to an expression, but I want to modify the expression before assigning. If the expression is nil, then the else block should be entered, otherwise the variable should be assigned to f(expression). Here is an example of what I would like to do:
let arr: [Int] = []
// Do stuff, maybe add elements to arr
guard let x = abs(arr.first) else { return } // Syntax error
// If arr was nonempty, then we want x = abs(arr.first!)
But Swift does not allow this syntax because abs requires a non-optional argument, and arr.first is optional. So is there any way to evaluate arr.first, and then if it is not nil to assign abs(arr.first!) to x? I know that I could do this with if-let or by using two variables (one from the guard-let and then one that gets assigned to the absolute value of that variable). But guard-let seems like the tool for the job, if only there were some way to accomplish this.
let arr:[Int] = [-1,1,3,-9]
guard let x = arr.first.flatMap({ $0 < 0 ? -$0: $0 }) else { return }
// ...
or (UPDATE based on dfri's notes)
// ....
let arr:[Int] = [-1,1,3,-9]
guard let x = arr.first.map(abs) else { return }
Optional(Some<Int>) -> Int -> Optional<abs(Some<Int)> -> Int ... meh
You could do a dirty guard let ..., let ... else fix as follows (forcing the binded certainly-not-nil value of x to become an optional which you subsequently immediately unwrap and bind to xAbs)
func foo() {
let arr: [Int] = [-1, 2, -3, 4]
guard let x = arr.first,
let xAbs = Optional(abs(xAbs)) else { return }
print(xAbs, xAbs.dynamicType)
}
foo() // 1 Int
This doesn't look very pretty however, and I would, personally, prefer adding an Int extension and make use of optional chaining, as I will cover next.
Instead: use extensions and optional chaining
Unless you explicitly need to store x as well as xAbs, an alternative and more Swifty approach is to use optional chaining in combination with a simple extension to Int:
extension Int {
var absValue: Int { return abs(self) }
}
func foo() {
let arr: [Int] = [-1, 2, -3, 4]
guard let xAbs = arr.first?.absValue else { return }
print(xAbs, xAbs.dynamicType)
}
foo() // 1 Int
Since arr.first is an optional Int variable, you can implement whatever method/computed property you wish onto self as an extension to Int, and access that method/property using optional chaining arr.first?.someMethod()/arr.first?.someProperty (as .absValue above).
Or, simply modify your arr.first (unwrapped) value after the guard let ... else block
I see no reason, however (other than the technical discussion) not to introduce an additional immutable holding the absolute value of x. This will also increase code readability, at least w.r.t. to the dirty guard let ..., let ... else fix above.
// ...
guard let x = arr.first else { return }
let xAbs = abs(x)
Or, if you find it acceptable for your xAbs property to be mutable, out of a theoretical perspective your could remove the middle-man immutable by using a guard var ... block rather than guard let ...
guard var xAbs = arr.first else { return }
xAbs = abs(xAbs)
This should probably only be used, however, if xAbs is to be mutated again (i.e., use immutables whenever you really don't need mutables, and never the other way around).
I think the cleanest and simplest solution would be like this:
guard let first = arr.first else { return }
let x = abs(first)
Now the calculation abs(first) is only reached if arr.first != nil.
What you want can be achieved using case let.
let arr: [Int] = [1,2,3,4]
guard let first = arr.first, case let absolute = abs(first) else { return }
// use `absolute`

Working with optionals in Swift programming language

As far as I know the recommended way to use optionals (Int in this example) is the following:
var one:Int?
if var maybe = one {
println(maybe)
}
Is it possible to use a shorter way to do something like the following?
var one:Int?
var two:Int?
var three:Int?
var result1 = one + two + three // error because not using !
var result2 = one! + two! + three! // error because they all are nil
Update
To be more clear about what I'm trying to do: I have the following optionals
var one:Int?
var two:Int?
var three:Int?
I don't know if either one or two or three are nil or not. If they are nil, I wan't them to be ignored in the addition. If they have a value, I wan't them to be added.
If I have to use the recommended way I know, it would look something like this: (unnested)
var result = 0
if var maybe = one {
result += maybe
}
if var maybe = two {
result += maybe
}
if var maybe = three {
result += maybe
}
Is there a shorter way to do this?
Quick note - if let is preferred for optional binding - let should always be used where possible.
Perhaps Optionals aren't a good choice for this situation. Why not make them standard Ints with a default value of 0? Then any manipulation becomes trivial and you can worry about handling None values at the point of assignment, rather than when you're working on the values?
However, if you really want to do this then a tidier option is to put the Optionals into an Array and use reduce on it:
let sum = [one,two,three,four,five].reduce(0) {
if ($1) {
return $0 + $1!
}
return $0
}
That's exactly the point of optionals — they may be nil or non-nil, but unwrapping them when they're nil is an error. There are two types of optionals:
T? or Optional<T>
var maybeOne: Int?
// ...
// Check if you're not sure
if let one = maybeOne {
// maybeOne was not nil, now it's unwrapped
println(5 + one)
}
// Explicitly unwrap if you know it's not nil
println(5 + one!)
T! or ImplicitlyUnwrappedOptional<T>
var hopefullyOne: Int!
// ...
// Check if you're not sure
if hopefullyOne {
// hopefullyOne was not nil
println(5 + hopefullyOne)
}
// Just use it if you know it's not nil (implicitly unwrapped)
println(5 + hopefullyOne)
If you need to check multiple optionals at once here there are a few things you might try:
if maybeOne && maybeTwo {
println(maybeOne! + maybeTwo!)
}
if hopefullyOne && hopefullyTwo {
println(hopefullyOne + hopefullyTwo)
}
let opts = [maybeOne, maybeTwo]
var total = 0
for opt in opts {
if opt { total += opt! }
}
(It seems you can't use the let optional binding syntax with more than one optional at once, at least for now...)
Or for extra fun, something more generic and Swifty:
// Remove the nils from a sequence of Optionals
func sift<T, S: Sequence where S.GeneratorType.Element == Optional<T>>(xs: S) -> GeneratorOf<T> {
var gen = xs.generate()
return GeneratorOf<T> {
var next: T??
do {
next = gen.next()
if !next { return nil } // Stop at the end of the original sequence
} while !(next!) // Skip to the next non-nil value
return next!
}
}
let opts: [Int?] = [1, 3, nil, 4, 7]
reduce(sift(opts), 0) { $0 + $1 } // 1+3+4+7 = 15