Friday, May 4, 2018

Swift 4 Introduction Series 1.9 - Swift Dictionary

Dictionary

Dictionary is collection type that consist of two component in each entries. For each entries in the collection, there is a key and a value. Each key is associated with a value. Therefore, the key must be unique. When we search for an item in the dictionary, we use the key as the search term. Key and value can be of different data type. Please note that dictionaries are unordered. A dictionary key must conform to the Hashable protocol.


Declared and Create A Dictionary

Create A Empty Dictionary

The syntax for creating an empty dictionary is as follows:


var <dictionary_name> = [<key_datatype> : <value_datatype>] ()


Example:


var sampleDic1 = [String: Double] ()

sampleDic1




Example 2:


var sampleDic2 = [Int: String] ()

sampleDic2




Create A Dictionary with Literal Values

To create a dictionary with literals we use the syntax as follows:

var <variable_name> = [<key1:value1, key2:value2, key3:value3, …. >]

We have an alternative syntax, where array data type is specified

var <variable_name>: [<key_datatype> : <value_datatype>] = [<key1:value1, key2:value2, key3:value3, …. >]


Example:


var callSign = ["A":"Alpha", "B":"Bravo"]

callSign




Example:


var userIDPassCode = [100:326542, 101:653285, 102:696542]

userIDPassCode




Data type is not required when declaring a dictionary with literal data values since the system can infer the data type from the data.


However, we can create a more specific dictionary so that we can prevent data entry error of different data type.


Example:


var salaryList: [String: Double] = ["Smith":10000, "Johnson":12000]

salaryList




In the example above, we can enter salary in whole number since we have specified that salary has to be in double.

Please note that, for data type that the system could not infer such as UInt or Float; we need to specified the data type.

Dictionary Basics

We will be using the following 2 dictionaries for the examples in this section. In the event that any of the dictionary is mess up or lost. Please use the snippet below to re-create the dictionaries:


var callSign = ["A":"Alpha","B":"Bravo","C":"Charlie","D":"Delta"]

var countryCode = [65:"SG",1:"US",44:"UK",852:"HK"]


Access Entire Dictionary

To access the entire dictionary, we can use the dictionary name as shown in the example below:


callSign
print(callSign)




Another example:


countryCode
print(countryCode)




Accessing Entries in Dictionary

To access entries, we just need to provide the key and the return data will provide the value. The syntax is as follows:


<dictionary_name>[<key>]


The previous expression will return  the value of the key.


Example:
This is a continuation from previous example, please do not delete the previous example.


callSign["A"]

let valueOfB = callSign["B"]




Please note that the return value is optional. If we access a key that does not exist, it will return nil.


Example:


callSign["H"]




Another Example:


countryCode[852]
countryCode[44]




Dictionary Count

We can find out the total number of entries in a dictionary by retrieving its read-only count property. The syntax is as follows:


<dictionary_name>.count


Example:
Using the call sign example above, we will retrieve total entries.


callSign.count




Empty Dictionary

To check if a dictionary is empty, we use the property isEmpty. The syntax is as follows:


<dictionary_name>.isEmpty


This property will return a boolean value.


Example:


callSign.isEmpty

var newDictionary = [Int:Int]()

newDictionary.isEmpty




We can also reset an existing dictionary to an empty dictionary. The syntax is:


<dictionary_name> = [:]


Example:
We continue using the dictionary callSign.


var testDictionary = callSign

testDictionary.isEmpty

testDictionary = [:]

testDictionary.isEmpty





Accessing and Extracting Entries in Dictionary

Accessing First Entry

We can retrieve the first entry using the property .first. The syntax is as follows:


<dictionary_name>.first


Please note that the entries in the dictionary is not in order. Therefore, the first entry may not be the first entry as we expected.


Example:


callSign.first
countryCode.first




As mentioned previously, the first entry on callSign is not "A", because dictionary is unordered. We do not have property to extract the last entry in a dictionary.


Maximum and Minimum Value

Since the entries in a dictionary can be of any data type. The implementation to extract the maximum or minimum value can be different. Furthermore,the system would not know if we are looking for the maximum in key or value.


Swift introduce a function where we can extract the maximum or minimum value provided we provide our own snippet of code.


<array_name>.max(by: {custom_code})
<array_name>.min(by: {custom_code})


Please note that the above function will return a single array item.


Example:


let maxOfCountry = countryCode.max(by:<)
maxOfCountry

let minOfCountry = countryCode.min(by: <)
minOfCountry




Another Example:


callSign.max(by: <)
callSign.min(by: <)




Other Method of Accessing Dictionary

We can still use the common method such as prefix and suffix to extract entries in dictionary. Since dictionary is unordered. It will be meaningless in extracting such value because we do not know what we are getting.

Similarly, we can still use drop method to remove entries, but the result is meaningless unless we know the order of dictionary. Furthermore, it is difficult to work with dictionary since most of the return is in array of tuples.

Similarly, the property of startIndex and endIndex does not serve much purpose either.


Getting Index of Search Entry

We can use index(forKey:) to find and match an entry in the dictionary. The return result is the index of the found item.


The syntax is as follows:


let/var <index> = <dictionary>.index(forKey: <key_to_search>)


Please note that the return result is an optional.


Example:

let keyD = callSign.index(forKey: "D")
callSign[keyD!]
let keyC = callSign.index(forKey: "C")
callSign[keyC!]

let key852 = countryCode.index(forKey: 852)
countryCode[key852!]
let key1 = countryCode.index(forKey: 1)
countryCode[key1!]

let keyNo = countryCode.index(forKey: 23)




As mentioned earlier, the returned result is an optional. Any key that is not found will return nil. See the last statement of the previous code. To use the optional we must unwrapped them, that is the reason we use (!) to extract the dictionary item.


For a better approach to implement the search method above, we could implement optional binding as shown in the example below:


if let gotCall = callSign.index(forKey: "C")
{
    callSign[gotCall]
} else {
    print("Not found")
}


Finding an Entry in Dictionary

When we access the dictionary, it will return nil if the key is not found.


Example:


callSign["A"]

callSign["S"]




As we can see from the example above, we can easily check if a key is present in the dictionary or not. What happen if we want to find values? We can use contains function as follows:


let <answer> = <dictionary>.values.contains(<values>)


We can also use this method to find keys as shown below. However, this method is redundant compare to direct access:


let <answer> = <dictionary>.keys.contains(<keys>)


The method will return a true or false answer.


Example :


let ans1 = callSign.keys.contains("B")
let ans2 = callSign.values.contains("Delta")
let ans3 = callSign.values.contains("Sierra")


Example 2:


let ans1 = countryCode.keys.contains(23)
let ans2 = countryCode.values.contains("US")
let ans3 = countryCode.values.contains("CA")




Finding Keys from Value

Let's say, we find a value but we do not know what is the associated keys. To reverse lookup a value in Swift, we can implement the methods as follows:


var countryCode = [65:"SG",1:"US",44:"UK",852:"HK"]

countryCode.values.contains("HK")

let indexForHK = countryCode.index(where: {$0.value.contains("HK")})

countryCode[indexForHK!].key


Another Example:


countryCode.values.contains("US")

let indexForUS = countryCode.index(where: {a in a.value.contains("US")})

countryCode[indexForUS!].key




Adding and Modifying Entries in Dictionary

Please note that we still use the same example without preserving additional items. The examples remain the same:


var callSign = ["A":"Alpha","B":"Bravo","C":"Charlie","D":"Delta"]

var countryCode = [65:"SG",1:"US",44:"UK",852:"HK"]


Adding and modifying entries uses the same syntax. To modify an entry in the dictionary, we just need to assign another value to the key. If the key is not found in the dictionary. The system will assume that it is a new entry. The syntax is as follows:


<dictionary_name>[<new/existing_key>] = <new_value>


Example:


callSign

callSign["A"] = "Apple"

callSign




Adding new entries example:


callSign["E"] = "Echo"
callSign["F"] = "Foxtroxt"
callSign["G"] = "Golf"
callSign




Amending entries:


callSign
callSign["A"] = "America"
callSign["B"] = "Brazil"
callSign["C"] = "China"
callSign["D"]
callSign




Using updateValue

Alternatively, we can use updateValue(_:forKey:) to modify or creating a new entry. The main differences is that when using updateValue function, it will return the old value if we are modifying an old entry and it will return nil for addition. The syntax:


<dictionary_name>.updateValue(<new_value>, forKey: <new/existing_key>)


Example


// Addition
callSign
callSign.updateValue("Sierra", forKey: "S")
callSign

// Modify Bravo to Brazil
callSign
let replacedValue = callSign.updateValue("Brazil", forKey: "B")
callSign




Sorting Dictionary

We can also sort a dictionary in order using the sorted method. The syntax is as follows:


let/var <sorted_dictionary> = <dictionary>.sorted(by: {custom_code})


Please note that once the method is executed, it will not change the existing dictionary. However, it will return a sorted list. The return is not actually a slice of dictionary but it is an array with tuples named key and value.


Example:


callSign
let sortedCallSign = callSign.sorted(by: <)
sortedCallSign




The following screenshot proves that the return list is actually an array of tuples:


Example 2:


callSign

let sortedDescendingCallSign = callSign.sorted(by: >)
sortedDescendingCallSign




To sort in descend order, we use the method sort(by:) and we use > sign for descending order.


Reverse Order in Dictionary

We can also reverse the order of a dictionary. This function makes sense when the dictionary is already in sorted order. To reverse the order method reverse. The syntax is as follow:


<dictionary>.reversed()


Similar to the sorted method, this method also return a reversed array list instead of a modifying existing dictionary.


Example:


ountryCode
let reversedList = countryCode.reversed()
reversedList




As you can see from the example, it does not make sense when the dictionary is unordered. Of course we can sort the dictionary, please note that the return will not be a dictionary but an array of tuples.


countryCode
let sortedList = countryCode.sorted(by: >)
let reversedList = Array(sortedList.reversed())
reversedList


Please note that sortedList is already an array, what we did is to reverse the array sortedList and at the same time convert the array slice into array.


Comparing Dictionary

We can compare 2 dictionaries using the comparison operator. Two dictionaries is the same when all the entries is the same. For comparing dictionary, we can only use equal (==) or not equal (!=) comparator.


Example:


callSign
var callSign1 = callSign
callSign1 == callSign
callSign1 != callSign
callSign1["B"] = "Brav0"
callSign1 == callSign
callSign1 != callSign




As we can see from the example above, The dictionary is consider different when the entries are different.


In the next example, we will find out if order matters in dictionary.


Example 2:


var callSign2 = ["A":"Alpha","B":"Bravo","D":"Delta","C":"Charlie"]
callSign2
callSign
callSign == callSign2
callSign != callSign2




Since dictionaries are unordered list, therefore the order does not make a difference.


Iteration Over a Dictionary

To run through every item in a dictionary, we use for-in loop. The syntax is as follows:


for <key_name, value_name> in <dictionary> {
<instruction_for_each_entry>
}


Example:


for (callSignLetter, callName) in callSign {
   
   print("The call name for \(callSignLetter) is \(callName).")

}




Please note that the first item is always keys and second item is always value regardless of how we name them.




We can also iterate a single item such as key or value. See example below:


for (callLetter) in callSign.keys {
   
   print("The call letter is \(callLetter).")

}




Example using values:


for (callName) in callSign.values {
   
   print("The call name is \(callName).")
}




Using Indices

Alternatively, we can use indices just to iterative the indices:


for index in callSign.indices {
   
   print("The entries is \(callSign[index]).")
   
}




Example 2:


for index in callSign.indices {
   
   print("The key \(callSign[index].key) value is \(callSign[index].value).")
   
}




To print dictionary in order, we have:


for (key, val) in callSign.sorted(by: <) {
   
   print("For key \(key), the entry is \(val).")
   
}




Summary:
  • To iterate each entry in dictionary use for-in loop with dictionaryName.indices
  • To extract both keys and value, use basic for-in loop. The first element is always key and second element is always values regardless of name used.


Convert Dictionary to Array

We can convert dictionary to array. The syntax is as follows:


let/var <array_name> = [<datatype>] (<dictionary_name>.<key/value>)


See the following examples:


let callLetterArray = [String](callSign.keys)

callLetterArray

let callNameArray = [String](callSign.values)

callNameArray




A better way is to convert a dictionary to an array of tuples. As we have know earlier, sort function return an array slice with tuples.


callSign
let arraySlice = callSign.sorted(by: <)
let arrayTuple = Array(arraySlice)
arrayTuple




Removing Entries in Dictionary

To modify an entry in the dictionary, we just need to assign nil to the key. The syntax is as follows:


<dictionary_name>[<existing_key>] = nil


Example:


//Removing Entries
callSign
callSign["A"] = nil
callSign["C"] = nil
callSign




Alternatively, we can also use removeValue(forKey:) function. Similarly, this function will return the removed value if the entry exists. Otherwise it will return nil. The syntax:


<dictionary_name>.removeValue( forKey: <existing_key>)


It return the removed value or nil


Example:


// Removing Entries using removeValue
callSign
callSign.removeValue(forKey: "C")
callSign.removeValue(forKey: "B")
callSign.removeValue(forKey: "V")
callSign




Remove All or Purge Existing Array

We can remove all item by using the method removeAll. The syntax is as follows:


<dictionary>.removeAll


Example:


var callSign = ["A":"Alpha","B":"Bravo","C":"Charlie","D":"Delta"]
callSign
callSign.removeAll()
callSign




Alternatively, we can also reset existing array to an empty array using the follow:


<dictionary> = [:]


Example:


var countryCode = [65:"SG",1:"US",44:"UK",852:"HK"]

countryCode
countryCode = [:]
countryCode



***

No comments:

Post a Comment