Function of swift, taking another function of its arguments - swift

func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, lessThanTen)
This is the example on The Swift Programming Language.
But in this example, I want to change
func lessThanTen(number: Int) -> Bool {
return number < 10
}
to
func lessThanBenchmark(number: Int, benchMark: Int) -> Bool {
return number < 10
}
so I also change this example to
func hasAnyMatches(list: Int[], condition: (Int, benchmark: Int) -> Bool) -> Bool {
for item in list {
if condition(item, benchmark) {
return true
}
}
return false
}
func lessThanBenchmark(number: Int, benchmark: Int) -> Bool {
return number < benchmark
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, lessThanBenchmark)
However, I got an error.
<REPL>:155:28: error: use of unresolved identifier 'benchmark'
if condition(item, benchmark) {
At last, I have to write like this style
func hasAnyMatches(list: Int[], condition: (Int, Int) -> Bool, benchmark:Int) -> Bool {
for item in list{
if condition(item, benchmark) {
return true
}
}
return false
}
func lessThanBenchmark(number: Int, benckmark: Int) -> Bool {
return number < benckmark
}
var numbers = [20, 19, 7,12]
hasAnyMatches(numbers, lessThanBenchmark, 10)
How can I pass benchmark to condition just as its own parameter?

benchmark is an argument of function.
condition: (Int, benchmark: Int) -> Bool
this line of code means that condition is a function that return Bool value and can takes two arguments: Int as first argument, and benchmark: Int is second argument.
You can call benchmark inside of condition.
smth like that:
func hasAnyMatches(list: Int[], condition: (Int, benchmark: Int) -> Bool) -> Bool {
for item in list {
if condition(item, benchmark: 15) {
return true
}
}
return false
}
15 is a value that you want to use

Related

Pass a conditional as an argument in Swift?

I was thinking of abstracting some conditional logic in my application. Suppose I have two functions in this simplified example:
func1(val1: Int, val2: Int, threshold: Int) -> Bool {
return (val1 == threshold && val2 == threshold)
}
func2(val: Int, thresholdHi: Int, thresholdLo: Int) {
return (val < thresholdHi && val > thresholdLo)
}
My idea is to make a function that performs a conditional check on a set of values.
funcIdea(vals[Int], conditional: ???) -> Bool {
for val in vals {
if !conditional(val) { return false; }
}
return true
}
func1(...){
return funcIdea([val1, val2], ???)
}
I think this is possible with either a closure or a function.
It is possible with a closure.
func funcIdea(vals: [Int], conditional: (Int)->Bool) -> Bool {
for val in vals {
if !conditional(val) { return false; }
}
return true
}
func func1(val1: Int, val2: Int, threshold: Int) -> Bool {
//return (val1 == threshold && val2 == threshold)
return funcIdea(vals: [val1, val2], conditional: { (val) -> Bool in
return val > threshold
})
}
You need to pass in a closure to your function, then you can use contains(where:) to check if the closure is true for all elements of the array. The double negation is necessary to allow for an early exit in contains(where:).
extension Array {
func allElementsSatisfy(_ condition: (Element)->(Bool)) -> Bool {
return !self.contains(where: { !condition($0)})
}
}
Then you can simply call it on any Array like this:
[1,2,3].allElementsSatisfy({$0 < 1}) // false
[1,2,3].allElementsSatisfy({$0 < 4}) // true
["a","b","c"].allElementsSatisfy({$0.count == 1}) // true
["a","b","c"].allElementsSatisfy({$0.count > 1}) // false

About Swift functions, named parameters, and type management

Suppose I have a function overloaded as such:
func doMath(mathOption: String) -> (Int...) -> Double {
...
return average
}
func doMath(mathOption: String) -> ([Int]) -> Double {
...
return average
}
Side note: Function average itself is overloaded to accept both an array as an input or a list of parameters.
Two questions:
1 - How do I reference which function I am referring to?
For example:
let doAverage = doMath(mathOption: "average")
How do I specify which doMath function I'm calling? Swift is confused and can't infer from the next line:
If I later write:
doAverage(1,2,3,4)
2 - How do I name parameters? The original average function is called thus:
average(nums: 1,2,3,4)
I have to name the parameters. Yet with doAverage, I can't name parameters because of how the return type is defined.
3 - How could I create a type (perhaps using struct?) to simplify this hypothetical code.
Thanks for any help, explanation, or answers you offer!
Edit, to clarify 3, here is the expanded version of the situation:
func sumAll(nums: [Int]) -> Double {
return Double(nums.reduce(0, { (a,b) in a+b}))
}
func sumAll(nums: Int...) -> Double {
return sumAll(nums: nums)
}
func average(nums: [Int]) -> Double {
return sumAll(nums: nums) / Double(nums.count)
}
func average(nums: Int...) -> Double {
return average(nums: nums)
}
func doMath(mathOption: String, nums: Int...) -> Double {
if mathOption == "average" {
return average(nums: nums)
} else {
return sumAll(nums: nums)
}
}
typealias mathReturnType1 = (Int...) -> Double
typealias mathReturnType2 = ([Int]) -> Double
func doMath(mathOption: String) -> mathReturnType1 {
return average
}
func doMath(mathOption: String) -> mathReturnType2 {
return average
}
I've used typealias to create two example types. Could a type be overloaded somehow to handle both situations? To me, this makes sense in that if the same function is being overloaded to handle different inputs, why not the type? Perhaps this is a naive perspective or perhaps there is a way to express what I'm thinking in Swift?
How to reference the function? Just specify the type!
func doMath(mathOption: String) -> (Int...) -> Double {
return { (values: Int...) -> Double in
return Double(values.reduce(0, +)) / Double(values.count)
}
}
func doMath(mathOption: String) -> ([Int]) -> Double {
return { (values: [Int]) -> Double in
return Double(values.reduce(0, +)) / Double(values.count)
}
}
let average1 = doMath(mathOption: "x") as (Int...) -> Double
print(average1(1, 2, 3))
or
let average1: (Int...) -> Double = doMath(mathOption: "x")
print(average1(1, 2, 3))
I would also advise to to name that type using a typealias.
Your second question - you cannot name parameters in function types.
You can pass the function you want done to doMath as a parameter. And use generics so you have some extensibility.
func doMath<T>(using op: (T) -> Double, with value: T) -> Double {
return op(value)
}
doMath(using: sumAll, with: [1,2,3])
// returns 6
Edit: It's having trouble with the variadic parameter.
Another edit: Found a workaround.
func doMath<T>(using op: ([T]) -> Double, with value: T...) -> Double {
return op(value)
}
func doMath<T>(using op: (T) -> Double, with value: T) -> Double {
return op(value)
}
doMath(using: sumAll, with: 1,2,3,4,5) //15
doMath(using: sumAll, with: [1,2,3,4,5]) // 15
Also, here's a prettier way to write that reduce:
Double(nums.reduce(0, +))

overload operator as generic function

i saw an example on "Pro swift" book.
it overloaded the operator, the first parameter "lhs" is a function that takes T -> U.
but "generateRandomNumber" function is Int -> Int
How can it work on >>> operator?
how does it work?
thanks.
import Foundation
infix operator >>> { associativity left }
func >>> <T, U, V>(lhs: T -> U, rhs: U -> V) -> T -> V {
return { rhs(lhs($0)) }
}
func generateRandomNumber(max: Int) -> Int {
let number = Int(arc4random_uniform(UInt32(max)))
print("Using number: \(number)")
return number
}
func calculateFactors(number: Int) -> [Int] {
return (1...number).filter { number % $0 == 0 }
}
func reduceToString(numbers: [Int]) -> String {
return numbers.reduce("Factors: ") { $0 + String($1) + " " }
}
let combined = generateRandomNumber >>> calculateFactors >>>
reduceToString
print(combined(100))
see the documentation about generics.
let combined = generateRandomNumber >>> calculateFactors >>> reduceToString
print(generateRandomNumber.dynamicType)
print(calculateFactors.dynamicType)
print(reduceToString.dynamicType)
print(combined.dynamicType)
/*
Int -> Int
Int -> Array<Int>
Array<Int> -> String
Int -> String
*/

How to use Anonymous Closure in Swift?

A closure function :
func makeIncrementer(externNumber:Int) -> (Int -> Int) {
func addOne(number: Int) -> Int {
return externNumber + number
}
return addOne
}
I want to use Anonymous Closure to achieve it, so I write this :
func my_makeIncrementer(externNumber:Int) -> (Int -> Int) {
return {
(number:Int)-> Int { // Error : cannot create a single-element tuple with an element label ;
return externNumber + number ;
} ;
}
}
You can see, Xcode throw a error
Error : cannot create a single-element tuple with an element label
You should re-look up the syntax here:
func my_makeIncrementer(externNumber:Int) -> (Int -> Int) {
return {
(number:Int)-> Int in
return externNumber + number
}
}

Im confused on how this function is being called, there is no call for it?

I'm confused on how getFunctionNeededForReference is running. There is no call for it and where are the functions returned to? where are they going? I know they are being referenced but where are the functions going to, there is not call for getFunctionNeededForReference in the beginning? there is no call sending the argument flag anyway?
func add ( a: Int , b : Int)-> Int {
//returing a result and not a variable
return a + b
}
func multiply ( a: Int, b: Int) -> Int{
return a * b
}
// declaring a function as a variable, it takes in 2 Ints and returns an Int
var f1 : (Int, Int)-> Int
f1 = add
f1 = multiply
// Function as a parameter
func arrayOperation (f: (Int, Int) -> Int , arr1: [Int] , arr2: [Int]) -> [Int]
{
// Declaring and initializing an empty array to return
var returningArray = [Int]()
for (i, val) in enumerate(arr1)
{
returningArray.append(f(arr1 [i], arr2 [i]))
}
return returningArray
}
arrayOperation(add, [2,3,4], [4,5,6])
arrayOperation(multiply, [2,3,4], [4,5,6])
//Function as a return value
func getFunctionNeededForReference (flag : Int) -> (Int,Int) ->Int
{
if flag == 0 {
return add
}else {
return multiply
}
}
What you've posted is just some example code showing things that Swift supports. It's not code that's useful for anything. It's just demonstrating Swift's syntax for first-class functions.
If you don't understand what “first-class functions” means, you can look up the term in your favorite search engine and find many explanations.