Browse Author: Shashikant Bhadke

Higher Order Function in Swift PART 2

Let’s start with FlatMap where few point need to cover. So lets begin,

Flatmap

Flatmap is used to flatten a collection of collections.

        let temp_Dictionary = [["k1":"v1","k2":"v2"],["k3":"v3","k4":"v4"]]
        let flatMap_1 = temp_Dictionary.flatMap { $0 }
        //[(key: "k2", value: "v2"), (key: "k1", value: "v1"), (key: "k3", value: "v3"), (key: "k4", value: "v4")]

It returns an array of tuples after flatmapping. We have to convert it to an array

        var flatMap_dictionary = [String: String]()
        flatMap_1.forEach {
            flatMap_dictionary[$0.0] = $0.1
        }
        //["k2": "v2", "k4": "v4", "k3": "v3", "k1": "v1"]

Sort

Sort an array simply by describing how you want the sort to work. You can do this simply by indicating the direction of the sort with a > or <.

So let’s try to sort simple name array as:

        let names = ["Sagar", "Savita", "Trupti", "Shravan", "Abdul", "Pragati", "amrita"]
        //["Abdul", "Pragati", "Sagar", "Savita", "Shravan", "Trupti", "amrita"]

Great, but what about “amrita” starts with a lower case letter?🤔🙄😟.

To ignore case, compare the lower case versions of the names:

        sortedNames = []
        sortedNames = names.sorted(by: {
            $0.lowercased() < $1.lowercased() 
        } 
        //["Abdul", "amrita", "Pragati", "Sagar", "Savita", "Shravan", "Trupti"]

That WORKS!!!!!!!!😀😃😃😄

Now let’s try out something more complex like below:,😮😯😧

For user-visible sorted lists, we should always use localized comparisons.

Fortunately, strings have another property called localizedLowercase.

        let sortedAcc_lastName = people.sorted(by: {
        $0.lastName.localizedLowercase < $1.lastName.localizedLowercase } )
        //[HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Shravan", lastName: "Gundawar"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Savita", lastName: "Kakade"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Trupti", lastName: "Karale"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Sager", lastName: "Rode"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "paragati", lastName: "Rode"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Adul", lastName: "Shaikh")]

This will sort according to lastName only.Obviously the first names need to be compared as well. You can achieve this by putting the two comparisons into a tuple.

       let sortedComplete = people.sorted(by: {
       ($0.firstName.localizedLowercase,$0.lastName.localizedLowercase) <
       ($1.firstName.localizedLowercase,$1.lastName.localizedLowercase)
        } )
       //[HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Adul", lastName: "Shaikh"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "paragati", lastName: "Rode"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Sager", lastName: "Rode"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Savita", lastName: "Kakade"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Shravan", lastName: "Gundawar"), HigherOrderFunctions.ViewController.Nano_Emp(firstName: "Trupti", lastName: "Karale")]

 

Contains

Generate a true/false by checking if any element in your array satisfies a condition. Related to filter, but returns a Bool, rather than an array.

eg. Let’s say we need to know if our fruits array contains a seven letter name.

         let sevenCharWord = names.contains { $0.characters.count == 7 }
         //true

Drop

Drops elements from your array while a condition is true, stops checking when it encounters an element that shouldn’t be dropped.

Let’s say we want to drop all elements at the beginning of the array that doesn’t contain the letter ‘s’.

           let name = names.drop { $0.contains("s") }
           //[ "Trupti",  "Abdul", "Pragati", "amrita"]
 

 

First

You’re probably familiar with the first property that retrieves the first element of an array, but did you know you can pass in a condition to get only the first element that meets that condition?

Let’s say we want the first element of the array that contains the letter ‘r’.

        let nameWithR = names.first { $0.contains("r") }
        //"Trupti"

ForEach

The forEach higher order function is a cool tool for your programming arsenal – basically short-hand for the for-inloop.

Let’s say we want print the lowercase version of every name in our Names array.

      names.forEach { print($0.lowercased(), terminator: " ") }
      //sagar savita trupti shravan abdul pragati amrita

Partition

The partition method partitions the elements of your array based on a condition. Elements that meet the condition are placed last in the array.

      names.partition(by: { $0.contains("i") })
      //["Sagar", "Abdul", "Shravan", "Trupti", "Savita", "Pragati", "amrita"]

Split

You may be familiar with the components method on String, used to split a String based on a separator.
To use the split method on a String, you would use it on the String.characters property, which is a String.CharacterType, which adopts the Collection protocol, giving characters access to many of the same cool higher order functions that Array has access to. Once you’ve separated String characters with split, you’ll have an array of something called a SubSequence, that you can pass in when initialising a String – you can do this on each element of your new array using the map higher order function to end up with an array of Strings.

For Example,

        let str = "I can't believe it! These higher order functions are like magic. Don't you think? Well, maybe not magic, but pretty useful all the same."
        let  sen1  =str.characters.spilt { $0 == "."  || $0 == "!"  || $0 == "?"  }
        let sen = sen1.map{ String($0) }
        //["I can\'t believe it", " These higher order functions are like magic", " Don\'t you think", " Well, maybe not magic, but pretty useful all the same"]

 

So here we have seen most of Higher Order Function. Hope you like this.
Thanks For Reading 😁🤪

Higher order functions in swift

As far as I understood, higher order functions are functions that takes another function/closure as argument and/or returns it.

Higher order functions are simply functions that operate on other functions by either taking a function as an argument, or returning a function. Swift’s Array type has a few methods that are higher order functions: sorted, map, filter, and reduce. These methods use closures to allow us to pass in functionality that can then determine how we want the method to sort, map, filter, or reduce an array of objects.
If you look around the internets the most commonly mentioned higher order functions in Swift are generally mapfilter, reduce and sort (or sorted). But there are so many more to play with!

Just take a look at Array – you will also find containsdropfirstflatMapforEachpartition  and split.

Map

Use map to loop over a collection and apply the same operation to each element in the collection.

Map on array:

Let’s assume we need to multiply each item by 10 in an array called numberArray

          let numberArray = [2,3,4,5,6,7,8]
          let emptyArray:[Int] = []
          //MARK:-Traditional Way
         for number in numberArray{
                    emptyArray.append(number*10)
         }
        //MARK:-
Higher Order Functions that is map

There are few form’s: long-form vs shorthand closure syntax preference.
        //1) Way
        emptyArray = []

        emptyArray = numberArray.map ( { (value:Int) -> Int in
               return value*10
})
        //2) Way
        emptyArray = []
        emptyArray = numberArray.map( { (value:Int) in
               return value*10
        })
//3) Way
        emptyArray = []
        emptyArray = numberArray.map {value in value*10}
//4) Way
        emptyArray = []
        emptyArray = numberArray.map {$0 * 10}

The map function has a single argument which is a closure (a function) that it calls as it loops over the collection. This closure takes the element from the collection as an argument and returns a result. The map function returns these results in an array.

Map on Dictionary:

        let reviews = [“likes”:50, “comments”:52]

Here, for the above dictionary, as we iterate over the collection our closure has arguments that are a String and a Int from the types of the key and value that make up each element of the dictionary. The return type can be an array of values (i.e., 50), values array with discounts or even an array of tuples. It’s all upto you.

         let reviewsCount = reviews.map { (key, value) in
                 return value
         }
         print(reviewsCount)
         //[50, 52]

Map on Custom Object:

    struct Person{
       let name:String
       let id:Int
           init(name:String, id:Int){
           self.name = name
           self.id = id
       }
    }
    let personDict = ["Palash":1,"Rahul":2,"Govind":3]
    let persons = personDict.map{ name, id in Person(name: name, id: id)}
    print(persons.first?.name)
    //Palash

Array count  Traditional Way Exe. time    Using Hight Order Function map Exe. time
   6930         0.0645290017127991                         0.00439298152923584

Filter

Use filter to loop over a collection and return an Array containing only those elements that match an include condition.

Filter on array:

Consider the following code to filter even numbers from an array of integers.Now, like map , there is a simple method to do the filtering stuff for collection types.The swift autocomplete shows the following if we try to use filter method for an Int array.
The filter method has a single argument that specifies the include condition. This is a closure that takes as an argument the element from the collection and must return a Bool indicating if the item should be included in the result. I have given the shorthand closure syntax example below.,

         //MARK:-Traditional Way
         emptyArray = []
         for no in numberArray{
             if no % 2 == 0{
                 emptyArray.append(no)
             }
         }

         //MARK:-Higher Order Functions
         emptyArray = []
         emptyArray = numberArray.filter{$0 % 2 == 0}

Filter on dictionary:

 The filter functions will call a closure called isIncluded by passing each key-value pair and do the condition check (here, it accepts a String and Doubleas arguments). Finally, based on the bool value returned, the filter function will decide whether or not to add the key-value pair in the returned array.
Filter function on dictionary returns an array of Tuples .

          let reviewsFilter = reviews.filter { (key, value) in
                  return value > 50
}
          print(reviewsFilter)

         //52

This can be further simplified as:

         let reviewsFilter1 = reviews.filter { $1 > 50}

       Note: $0 is the key, $1 is the value

Array count  Traditional Way Exe. time    Using Hight Order Function map Exe. time
 3300           0.000292956829071045                    0.00520197877883911

Reduce

Combines all items in a collection to create a single value.

The most versatile function reviewed here is reduce. Reducing a sequence means transforming many items into a single item. For example, an array of integers could be reduced to the sum of every integer in the array. In this case, a sequence of integers is reduced to a single integer.

        //MARK:-Traditional Way
        var sum = 0
        for no in numberArray{
sum += no
        }

The two parameters in reduce function are a starting value and a function respectively. The function takes a running total and an element of the array as parameters, and returns a new running total.

        //MARK:-Higher Order Functions
        //1 Way 
        var  sum = numberArray.reduce(0, {$0 + $1})
        //2 Way 
        var sum = numberArray.reduce(0,+)

In above scenario, instead of the closure, we could also pass basic operator functions like +, -, *, / . So we can say reduce is used to combine all items in a collection to create a single new value.

Reduce on dictionary

        let totalReviews = reviews.reduce(0) { (result, tupleOfKeyAndValue) in
                   return result + tupleOfKeyAndValue.value
}

Flatmap

When implemented on sequences : Flattens a collection of collections.

There are two versions of this function: one that supports mapping optional values and another that supports mapping a sequence of sequences, such as [[Int]] (i.e. an array of array of integers)

let tempArray = _flatMap([“Hi”,” “,“there”,” “, nil,“😁!!!!”]) { $0 }
print(tempArray)

//Hi there 😁!!!!

This function is like a mixture of map and filter. It creates a sequence of mapped values, but a mapped value is not added to the output sequence when the closure returns nil. In that sense, returning nil is similar to returning false from a closure passed to the filter function.

 

Happy Coding… 🙂📱😁
I will show the usage of remaining higher order function in my next post.

Animation like floating Buttons.

Hi all, today we will check out simple but cool floating buttons using UIViewAnimations methods. So, in this we are going to show 4 buttons which came out upside from another button. Here we are using constraints of  buttons, button and UIViewAnimations. Let’s start with  adding constraint to each buttons.
1) Setting constraints for buttons:-    

Add constraint such that bottom constraint of 2nd button to 1st bottom similarly do for 3rd to 4th and 4th to 5th button. I am doing this because when i am going to update value for constraint is same and due to that i can manage spacing between them.
I have set my button’s size to 45*45 and other constraints to ZERO. After setting constraint you should see only single button which overlaps other buttons.  And I need IBActions of  all 4 buttons. 

2) Adding Animations to IBAction methods:-    

Add Following line code in your application

if !flag{
  UIView.animate(withDuration: 0.20, animations: {
     self.btn1bottomCons.constant = 55
}, completion: { (isTrue) in
  if isTrue{
     UIView.animate(withDuration: 0.15, animations: {
     self.btn2bottomCons.constant = 55
}, completion: { (isTrue) in
        if isTrue{
UIView.animate(withDuration: 0.10, animations: {
            self.btn3bottomCons.constant = 55
})
}
})
}
})
}else{
UIView.animate(withDuration: 0.5, animations: {
     self.view.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
})
  btn1bottomCons.constant = 0
  btn2bottomCons.constant = 0
  btn3bottomCons.constant = 0
UIView.animate(withDuration: 0.10, animations: {
})
}
flag = !flag

Here flag is Bool value used to toggle the buttons. btn1bottomCons, btn2bottomCons, btn3bottomCons and btn4bottomCons are the constraint which we have created initially. When flag is false set constraint value to 55 otherwise set 0. Please observer that i have set value in the completion block of other button and duration of animation 0.20, 0.15, 0.10. So that at end animation must be fast.
If you like to create your own custom completion handle here is one example given below,….


func yourFunctionName(isFlag:Bool,str:String,isCompleted:(_ success: String)-> Void){
for _ in 01000 {
//make delay
}
var str2 = “Hi “
str2 += “Shashi!, Yours String is—> “
str2 += str
isCompleted(str2)// Pass your result to completion block at the end😎
}

Now call the function as below,

yourFunctionName(isFlag: true, str: “😜“) { (str_temp) in
print(“—-===>***”,str_temp,”***<===—-“)
}

 

3) Run the App:-    

Run the code and click the button and observe there and say “there is no animation happening here😡” .

To solve this issue you need to update layout which is single line of code more powerful because I observer that due to that viewDidload() call again😵 yes.

So you need to add the following line of code

self.view.layoutIfNeeded()

So final code will be,——>        

        if !flag{

            UIView.animate(withDuration: 0.20, animations: {

                self.btn1bottomCons.constant = 55

                self.view.layoutIfNeeded()

            }, completion: { (isTrue) in

                if isTrue{

                    UIView.animate(withDuration: 0.15, animations: {

                        self.btn2bottomCons.constant = 55

                        self.view.layoutIfNeeded()

                    }, completion: { (isTrue) in

                        if isTrue{

                            UIView.animate(withDuration: 0.10, animations: {

                                self.btn3bottomCons.constant = 55

                                self.view.layoutIfNeeded()

                            })

                        }

                    })

                }

            })

        }else{

            UIView.animate(withDuration: 0.5, animations: {

                self.view.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)

            })

            btn1bottomCons.constant = 0

            btn2bottomCons.constant = 0

            btn3bottomCons.constant = 0

            UIView.animate(withDuration: 0.10, animations: {

                self.view.layoutIfNeeded()

            })

        }

        flag = !flag

 

And my original project is on this Link:—–>https://github.com/ShashikantBhadke/ADMobs