I am beginner in swift and I'm doing exercises to learn.
I have to filter any numbers that are even, sort the array, map them to string and print the result one item per line.
The problem is, when I call the function, I´m not able to chain the closures, and it only prints the third function.
import Foundation
let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]
func doImportantWorkChain (first: ([Int]) -> [Int], second: ([Int]) -> [Int], third: ([Int]) -> [String]) {
first(luckyNumbers)
second(luckyNumbers)
third(luckyNumbers)
third(luckyNumbers).forEach {
print($0)
}
}
doImportantWorkChain { number in
return number.filter {
return $0.isMultiple(of: 2)
}
} second: { number in
return number.sorted {
return $0 < $1
}
} third: { number in
return number.map {
("\($0) is the lucky number")
}
}
Output
7 is the lucky number
4 is the lucky number
38 is the lucky number
21 is the lucky number
16 is the lucky number
15 is the lucky number
12 is the lucky number
33 is the lucky number
31 is the lucky number
49 is the lucky number
Output I have to get
4 is the lucky number
12 is the lucky number
16 is the lucky number
38 is the lucky number
I know that I have to use: luckyNumbers.first { }.second { }
When I try to write like this Xcode give me error: value of type '(([Int]) -> [Int], ([Int]) -> [Int], ([Int]) -> [String]) -> ()' has no member 'first'
So I erase first and give me this errors:
Expected member name following '.'
Top-level statement cannot begin with a closure expression
Value of type '(_) -> _' has no member 'second'
doImportantWorkChain.first{ number in
return number.filter {
return $0.isMultiple(of: 2)
}
}.second{ number in
return number.sorted {
return $0 < $1
}
}.third{ number in
return number.map {
("\($0) is the lucky number")
}
}
Also I try to chain it when when I call them inside the function but doesn't work either.
CodePudding user response:
You are not using results from previous functions to next.
If you do so then you will end up with error on this third(luckyNumbers).forEach
line as function expected [Int] and you will be going to pass [String] as output from this third(luckyNumbers)
call.
To work this code, you can have following modifications and run
let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]
func doImportantWorkChain (first: ([Int]) -> [Int], second: ([Int]) ->
[Int], third: ([Int]) -> [String]) {
let first_result = first(luckyNumbers)
let second_result = second(first_result)
let third_result = third(second_result)
for result in third_result {
print(result)
}
}
doImportantWorkChain { number in
return number.filter {
return $0.isMultiple(of: 2)
}
} second: { number in
return number.sorted {
return $0 < $1
}
} third: { number in
return number.map {
("\($0) is the lucky number")
}
}
CodePudding user response:
As the first answer suggested, the issue is that the result of a closure should be used in the next closure.
The fastest way to get the output you are looking for
func doImportantWorkChain(first: ([Int]) -> [Int],
second: ([Int]) -> [Int],
third: ([Int]) -> [String]) {
third(second(first(luckyNumbers))).forEach {
print($0)
}
}
However, this is not really chaining
functions together and it is doing what the first answer with and just reduces your lines of code but there is no real upgrade in this.
The right way (IMO) to get the output you are looking for
Chaining would be something that I believe one of the commenters suggested is using the filter, sort and map functions directly on luckyNumbers
to get your desired output:
luckyNumbers
.filter { $0.isMultiple(of: 2) }
.sorted() { return $0 < $1 }
.map { ("\($0) is the lucky number") }
.forEach { print($0) }
A way that is chaining, will give you the desired output but I don't know why you would ever use this
If you think about what you need to do, to achieve some sort of chaining, you need to create your own higher order
functions like filter, map etc
with the same signatures as your closures and then executing the closures.
I did this by creating an extension
for Int
arrays
extension Array where Element == Int
{
func apply(_ operation: ([Int]) -> [Int]) -> [Int]
{
return operation(self)
}
func apply(_ operation: ([Int]) -> [String]) -> [String]
{
return operation(self)
}
}
Then you can achieve chaining and get your desired result
func doImportantWorkChain(first: ([Int]) -> [Int],
second: ([Int]) -> [Int],
third: ([Int]) -> [String]) {
luckyNumbers
.apply(first)
.apply(second)
.apply(third)
.forEach { print($0) }
}
Again, this might be a nice exercise to work your brain and explore the language and its capabilities but I don't think you will ever really use this.
All three of the above ways will give you this output:
4 is the lucky number
12 is the lucky number
16 is the lucky number
38 is the lucky number