I was reading this article about high order functions
https://medium.com/#mimicatcodes/simple-higher-order-functions-in-swift-3-0-map-filter-reduce-and-flatmap-984fa00b2532
then I started playing around with them and found this:
let someArray = [1, 2, 3, 4, 5]
let newArray = someArray.map {
print($0)
$0 * 2
}
print(a)
this would return empty values in newArray
while removing the print function or specifically setting the function's return type would work:
let a = someArray.map { number -> Int in
print(number)
return number * 2
}
print(a)
Any explanations?
This is because if you use Shorthand Argument Names in closure you have to return from very first line i.e. inline return.
In your first closure you'r first line is print() which returns nothing.
If you do like this:
let newArray = someArray.map {
$0 * 2
}
Or simply this:
let newArray = someArray.map { $0 * 2 }
you will get the result.
Read more about this here in developer docs.
Update
As shown by #hamish, multiple calculations can be done with shorthand arguments but then we need to explicitly mention data type of result and also return statement as:
let newArray: [Int] = someArray.map {
print($0)
return $0 * 2
}
If you do not use return in a closure that should return something, then the result of the first statement is returned. In this case void (aka the empty tuple: () ) which is returned by the print function.
Calling functions like print in a map closure is bad practice since it could have side effects and should be avoided.
Related
I am trying to find out the count of first and last name value exit in an array of a and return a result as[String: Int] a count with the same key.
I am getting error on this line newResult[arg.key] = counts . Cannot assign value of type 'Int' to type 'Int?
func abbreviation(a:[String], b: [String : String]) ->[String : Int] {
let dict = b.reduce([String : Int]()){ (result, arg) in
var newResult = result
let counts = a.reduce(0) { (newcount, value) -> Int in
let count = newcount + (value.components(separatedBy:arg.value).count - 1)
return count
}
return newResult[arg.key] = counts
}
return dict
}
//result
let dict = abbreviation(a:["This is chandan kumar and chandan kumar and new chandan","check chandan kumar","non ame"], b:["first":"chandan","last":"kumar"])
The error message is so confusing, and you may need to be accustomed to take it as Swift cannot infer some types in this context.
With this line:
return newResult[arg.key] = counts
Do you know what is returned with this return-statement? It's a Void, also known as an empty tuple. (Void is the result type of assignment statement in Swift.) You might have expected newResult would be the result of the closure, but that sort of things would not happen unless you explicitly write return newResult.
Try changing the line in to the following:
newResult[arg.key] = counts
return newResult
You are trying to return the result of an assignment expression:
return newResult[arg.key] = counts
or maybe you are trying to assign to the result of a return statement? This line doesn't make sense which way you look at it. You should separate the two things you are doing:
newResult[arg.key] = counts
return newResult
It seems like in this situation, you should use the other overload of the reduce method - reduce(into:_:).
The reduce method you are currently using requires you to return a new value every time, but you are just adding a KVP to a dictionary i.e. modifying an existing value. This means that you are creating lots of copies of dictionaries. This is a good sign that reduce(into:_:) might be a better fit.
func abbreviation(a:[String], b: [String : String]) ->[String : Int] {
// notice the parameter label "into:"
let dict = b.reduce(into: [String : Int]()){ (result, arg) in
let counts = a.reduce(0) { (newcount, value) -> Int in
let count = newcount + (value.components(separatedBy:arg.value).count - 1)
return count
}
result[arg.key] = counts // with reduce(into:_:), you don't return anything, just modify the first argument
}
return dict
}
I'm trying to understand better the closures in swift and I've tried to create a silly function with a completion handler that returns a value but this value goes nowhere...
here's what I did..
func productToString(num: Int,num2: Int,completion: (Int)->String){
let result = num * num2
completion(result)
}
let numberToString = productToString(num: 3, num2: 6) { (res) -> String in
return "string:\(res)"
}
print(numberToString) // print statement prints ()
when I tried to save this return value in a variable it returned just a pair of curvy brackets.
how should I use this return value?
You're returning the value into the productToString function but not doing anything else with it.
func productToString(num: Int,num2: Int,completion: (Int)->String){
let result = num * num2
completion(result) // <--- Your return value ends up here
}
If you want to print the result you have to return it again out of the productToString function.
func productToString(num: Int,num2: Int,completion: (Int)->String) -> String {
let result = num * num2
return completion(result)
}
Sidenote: The empty brackets that are printed are an empty tuple which is equivalent to Void in Swift.
I'm trying to get used to generics (never used them in objc) and want to write a toy function that takes an object of any type () and returns the first and last element. Hypothetically, I'd only use this on an array or a string - I keep getting an error that has no subscript members. I totally understand that the error message is telling me swift has no clue that T may potentially hold a type that does have subscripts - I just want to know how to get around this.
func firstAndLastFromCollection<T>(a:T?) {
var count: Int = 0
for item in a as! [AnyObject] {
count++
}
if count>1 {
var first = a?[0]
var last = a?[count-1]
return (first, last)
}
return something else here
}
Do I need to typecast somewhere here (which would kind of defeat the purpose here, as I'd need to downcast as either a string or an array, adding code and lessening how generic this func is)?
If you want to return the first and the last element then it's probably safe assuming the input param is an array of some kind of type.
So you can implement your function this way
func firstAndLast<T>(list:[T]) -> (first:T, last:T)? {
guard let first = list.first, last = list.last else { return nil }
return (first, last)
}
The function does return a tuple of 2 element, both have the same type of the generic element of the input array.
The returned tuple is an option because if the array is empty then nil is returned.
Examples
let nums = firstAndLast([1,2,3,4])
let words = firstAndLast(["One", "Two", "Three"])
As you can verify the type of the generic element into the array becomes the type of the elements inside the tuple.
In the example above nums is inferred to be (Int, Int)? and words (Words, Words)?
More examples
let emptyList: [String] = []
firstAndLast(emptyList) // nil
Extension
Finally you can also write this code as an extension of Array.
extension Array {
var firstAndLast: (first:Element, last:Element)? {
guard let first = self.first, last = self.last else { return nil }
return (first, last)
}
}
Now you can write
let aCoupleOfShows = ["Breaking Bad", "Better Call Saul", "Mr Robot"].firstAndLast
Again, if you check the type of the constant aCoupleOfShows you'll see that is a (first: String, last: String)?. Swift automatically did infer the correct type.
Last example
In the comments you said you wanted the first and last chars of a String. here it is the code if you use the extension above
if let chars = Array("Hello world".characters).firstAndLast {
print("First char is \(chars.first), last char is \(chars.last) ")
}
//>> First char is H, last char is d
If we are talking about collections, let's use the CollectionType:
func firstAndLastFromCollection<T: CollectionType>(a: T) -> (T.Generator.Element, T.Generator.Element)? {
guard !a.isEmpty else {
return nil
}
return (a.first!, a.lazy.reverse().first!)
}
print(firstAndLastFromCollection(["a", "b", "c"])) // ("a", "c")
print(firstAndLastFromCollection("abc".characters)) // ("a", "c")
print(firstAndLastFromCollection(0..<200)) // (0, 199)
print(firstAndLastFromCollection([] as [String])) // nil
If you specify your generic type to also conform to bidirectional index:
func firstAndLastFromCollection<T: CollectionType where T.Index : BidirectionalIndexType>(...) -> ...
then you can call last directly:
return (a.first!, a.last!)
If we decide to implement it using a category, we don't need generics at all:
extension CollectionType {
func firstAndLast() -> (Generator.Element, Generator.Element)? {
guard !self.isEmpty else {
return nil
}
return (self.first!, self.lazy.reverse().first!)
}
}
extension CollectionType where Index: BidirectionalIndexType {
func firstAndLast() -> (Generator.Element, Generator.Element)? {
guard !self.isEmpty else {
return nil
}
return (self.first!, self.last!)
}
}
print("abc".characters.firstAndLast())
Swift is a protocol oriented language. Usually you will find yourself extend protocols more than extending classes or structs.
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`
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