Search This Blog

Wednesday, July 4, 2018

Coding Task in Swift. Find odd occurring number in array

Task: Given an array of of repeating integer numbers. All numbers are repeated an even number of times, except for one. Find that odd occurring number.

Solution with two for loops

Example of an array, there is one odd occurring number, it is 9.
let array = [1, 2, 3, 9, 3, 2, 1]
Algorithm is following:
  1. Create dictionary (hash table) with keys of type Int and values of type Int. Key is number itself, value is counter of this number.
  2. First for loop. For each number in array
    • If number already exist in dictionary then increment counter for this number by 1
    • Else add this number to dictionary as key and assign value of 1 to this number
  3. Second for loop. For each key/value pair in dictionary
    • If the value is odd (remainder of division by 2 is not 0) then return key (key is the number)
  4. By default return nil from function. So function will return type optional type Int?
func findOdd1(_ array: [Int]) -> Int? {
    var table = [Int: Int]()
    array.forEach {
        if let count = table[$0] {
            table[$0] = count + 1
        } else {
            table[$0] = 1
        }
    }
    for pair in table {
        if pair.value % 2 != 0 {
            return pair.key
        }
    }
    return nil
}
There are two for loop for N elements, so time complexity for each will be 0(n). It will give us O(n) + O(n) that equals to O(2n) that equals to O(n) because we can drop coefficients when estimate the complexity.
Get result and check for errors
findOdd1(array) // 9
assert(findOdd1(array) == 9, "Error happened")
// Time Complexity is O(n) + O(n) because of two for loop,
// but it gives O(2n) that is equivalent to O(n)

Optimised Solution

There are ways to modify and optimize first solution. When we iterate over elements in array we can check if number occur even number of times we can remove it from dictionary. So as result we will have in dictionary only numbers that occurred odd number of times. Here we have only one such number in array, so we return first key from dictionary.
// Optimised solution
func findOdd2(_ array: [Int]) -> Int? {
    var table = [Int: Bool]()
    array.forEach {
        if table[$0] != nil {
            table[$0] = nil
        } else {
            table[$0] = true
        }
    }
    return table.keys.first
}
There is only one for loop over n elements is array. So time complexity will be O(n)
Get result and check for errors
findOdd2(array) // 9
assert(findOdd2(array) == 9, "Error happened")
// Time Complexity is O(n) - we remove one for loop.

Source Code

Source code can be found here on GitHub

Monday, July 2, 2018

iOS Swift. How to calculate the mean and median of an array

Theory

Given an unsorted array on integer elements. Calculate mean and median for this array.
Let's define what is a mean and what is median.

Mean of an array = (sum of all elements) / (number of elements)

For correctly calculate median of the array we need to sort array first.
Median of a sorted array  depends on count of elements in array: even or odd.
  • If count of elements is odd then median is middle element.
  • If count of elements is event then median is average of middle two elements. 

Calculate Mean of the array

Calculate mean of the array is pretty easy task. We just cum all elements of array and then divide this sum by count of elements. One thing to notice, for calculating sum of elements we can use reduce function.
func calculateMean(array: [Int]) -> Double {
    
    // Calculate sum ot items with reduce function
    let sum = array.reduce(0, { a, b in
        return a + b
    })
    
    let mean = Double(sum) / Double(array.count)
    return Double(mean)
}

calculateMean(array: [1, 4, 5, 6, 7, 12, 14, 18, 19, 20, 22, 24])
// 12.66666666666667
For more handy usage we can create extension with calculated property mean.

Extension for Array Type 
extension Array where Element == Int {
    
    var mean: Double {
        let sum = self.reduce(0, { a, b in
            return a + b
        })
        
        let mean = Double(sum) / Double(self.count)
        return Double(mean)
    }
}

[1, 4, 5, 6, 7, 12, 14, 18, 19, 20, 22, 24].mean
// 12.66666666666667

Calculate Median of the array

For calculate median of the array we need to sort array first. Then, calculate the median value,  depending on whether the number is even or odd.
func calculateMedian(array: [Int]) -> Double {
    // Array should be sorted
    let sorted = array.sorted()
    let length = array.count
    
    // handle when count of items is even
    if (length % 2 == 0) {
        return (Double(sorted[length / 2 - 1]) + Double(sorted[length / 2])) / 2.0
    }
    
    // handle when count of items is odd
    return Double(sorted[length / 2])
}

calculateMedian(array: [1, 2, 3, 4, 5, 6, 7, 8, 9]) // 5
// odd numbers of items, so median = 5

calculateMedian(array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) // 5.5
// even numbers of items, so median = (5 + 6) / 2 = 5.5
For more handy usage we can create extension with calculated property median.

Extension for Array Type
extension Array where Element == Int {
    
    var median: Double {
        let sorted = self.sorted()
        let length = self.count
        
        if (length % 2 == 0) {
            return (Double(sorted[length / 2 - 1]) + Double(sorted[length / 2])) / 2.0
        }
        
        return Double(sorted[length / 2])
    }
}

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].median // 5.5
[1, 2, 3, 4, 5, 6, 7, 8, 9].median // 5

Source Code

Source code for this post could be found here on GitHub.

Sunday, July 1, 2018

Generating random and using It in Swift

Default Methods

For generating random numbers in swift, the following functions are used:
  • arc4random() returns a random integer number in the range of 0 to 4 294 967 295 (it is UInt32.max)
  • drand48() returns a random float point number in the range of 0.0 to 1.0
  • arc4random_uniform(N) returns a random integer number in the range of 0 to N - 1

Let's see examples of how this functions work:
arc4random() // 107985684

drand48() // 0.3964647737602753

arc4random_uniform(10) // 4
But what if we need to implement more advanced requirements for generating random numbers. Let's explore possible situations where we generating random numbers and using it.

Generate Random Integer with Upper Bound

For generating random integer in range between 0 and upper bound we use function

rc4random_uniform(N)

This function will return random integer number in the range of 0 to N - 1. So, for example, if N = 42 then maximum number that can be generate will be 41 and minimum will be 0.
rc4random_uniform(42)
This function takes one parameter of type UInt32 and returns value of type UInt32
func arc4random_uniform(_ __upper_bound: UInt32) -> UInt32
So, if you work with values of type Int you have to convert values to type UInt32 when parameter passed to function and convert back to Int when getting result.
let number: Int
number = Int(arc4random_uniform(42))

let inputNumer: Int = 100
let outputNumber: Int
outputNumber = Int(arc4random_uniform(UInt32(inputNumer)))
It is not very handy always do this conversion when generating random numbers. Let's make a function for this:
func random(n: Int) -> Int {
    return Int(arc4random_uniform(UInt32(n)))
}

let n: Int
n = random(n: 99)
This function takes one parameter of type Int and return result in range between 0 and N-1 of type Int.

To make it more useful we can create extension for type Int and generating of random integers will be availbale everywhere in code. We also can check for sign before passed parameter because UInt32 type is unsigned type and in case of negative value passed we need to get absolute value from input passed parameter. This method is static and will be available for whole Int type, there is no need to create instance of Int type.
extension Int {
    
    static func random(_ n: Int) -> Int {
        if n < 0 {
            return -Int(arc4random_uniform(UInt32(abs(n))))
        } else if n > 0 {
            return Int(arc4random_uniform(UInt32(n)))
        } else {
            return 0
        }
    }
}

Int.random(-100) // return in range between -99 and 0
But we can create also an instance method in extension. In this case instance of Int type will be used as upper bound for random number generation function.
extension Int {
   
    func random() -> Int {
        if n < 0 {
            return -Int(arc4random_uniform(UInt32(abs(self))))
        } else if n > 0 {
            return Int(arc4random_uniform(UInt32(self)))
        } else {
            return 0
        }
    }
}

65.random()

Tuesday, June 26, 2018

How to shuffle an array in Swift

Given a task - write a function for shuffle array. Let's start from simple solution. This method called Pencil and paper method

Example of function which shuffle array
import Foundation

let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

func shuffle(array: [Int]) -> [Int] {
    var arrayCopy = array
    var randomArray = [Int]()
    for _ in array {
        let randomIndex = Int(arc4random_uniform(UInt32(arrayCopy.count)))
        let removedValue = arrayCopy.remove(at: randomIndex)
        randomArray.append(removedValue)
    }
    return randomArray
}

let shuffledArray = shuffle(array: array)
print(array) //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(shuffledArray) //[7, 6, 9, 2, 8, 4, 3, 1, 5, 10]
Function shuffle, that provided below, works by following algorithm:
  1. Make copy of incoming array to variable arrayCopy (we will remove items from this copy)
  2. Make new empty array randomArray(we will add new values to this array)
  3. For each item in copied array
    1. Generate random index from 0 to arrayCopy length
    2. Remove item with random index from arrayCopy (when remove we can store removed item)
    3. Add removed item to randomArray
  4. Return randomArray


Making Extension for shuffle array

For more handy usage let's move this code to extension

Example of extension for shuffle array
extension Array {
    
    func shuffle() -> [Element] {
        var arrayCopy = self
        var result = [Element]()
        for _ in self {
            let randomIndex = Int(arc4random_uniform(UInt32(arrayCopy.count)))
            let removedItem = arrayCopy.remove(at: randomIndex)
            result.append(removedItem)
        }
        return result
    }
}

let array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(array2) //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(array2.shuffle()) //[5, 9, 6, 10, 2, 7, 1, 3, 8, 4]

let strings = ["one", "two", "three", "four", "five"]
print(strings) //["one", "two", "three", "four", "five"]
print(strings.shuffle()) //["five", "four", "one", "three", "two"]
The algorithm remains the same. But for now, because we use extension, any array can be shuffled, as we can see above now we can shuffle array of strings too.

Mutating self extension method
We can add modified version of our extension which modify current array in-place without return new array.

Example of extension which shuffle current array in-place
extension Array {
    
    mutating func shuffleInline() {
        var result = [Element]()
        for _ in self {
            let randomIndex = Int(arc4random_uniform(UInt32(self.count)))
            let removedItem = self.remove(at: randomIndex)
            result.append(removedItem)
        }
        self = result
    }
}

var array3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(array3) //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
array3.shuffleInline()
print(array3) //[3, 1, 4, 6, 2, 5, 9, 10, 7, 8]

Complexity of Pencil and paper algorithm

Complexity of this algorithm will be O(nˆ2) because
  • O(n) is for one 'for loop'
  • O(n) is for removing from array


Model Shuffle Algorithm

How we can improve time complexity of shuffling? There is Modern method which allow us to get linear O(n) complexity. It is because we have only one loop over the array and swap random item on each iteration.

Example of shuffle function implemented modern algorithm 
func shuffleModern(array: [Int]) -> [Int] {
    var length = array.count
    var arrayCopy = array
    for _ in array {
        let randomIndex = Int(arc4random_uniform(UInt32(length)))
        if length - 1 != randomIndex {
            arrayCopy.swapAt(length - 1, randomIndex)
        }
        length -= 1
    }
    return arrayCopy
}

let array4 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(array4) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(shuffleModern(array: array4)) //[9, 6, 7, 10, 2, 8, 1, 4, 3, 5]

Generic function
We also can make our function generic and apply it to array of any type, for example for array of strings.

Example of generic implementation
func shuffleModern<T>(array: [T]) -> [T] {
    var length = array.count
    var arrayCopy = array
    for _ in array {
        let randomIndex = Int(arc4random_uniform(UInt32(length)))
        if length - 1 != randomIndex {
            arrayCopy.swapAt(length - 1, randomIndex)
        }
        length -= 1
    }
    return arrayCopy
}

let strings2 = ["one", "two", "three", "four", "five"]
print(strings2) //["one", "two", "three", "four", "five"]
print(shuffleModern(array: strings2)) //["five", "four", "one", "three", "two"]
Also let's create two extensions as before: 1) will return new shuffled array 2) will shuffle array in-place

Example of extension with modern shuffle algorithm (Immutable and In-place)
extension Array {
    
    func shuffleModern() -> [Element] {
        var arrayCopy = self
        var length = arrayCopy.count
        for _ in arrayCopy {
            let randomIndex = Int(arc4random_uniform(UInt32(length)))
            if length - 1 != randomIndex {
                arrayCopy.swapAt(length - 1, randomIndex)
            }
            length -= 1
        }
        return arrayCopy
    }
    
    mutating func shuffleModernInline() {
        var length = self.count
        for _ in self {
            let randomIndex = Int(arc4random_uniform(UInt32(length)))
            if length - 1 != randomIndex {
                swapAt(length - 1, randomIndex)
            }
            length -= 1
        }
    }
}

var array5 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(array5) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(array5.shuffleModern()) // [2, 6, 10, 5, 4, 7, 3, 8, 9, 1]
array5.shuffleModernInline()
print(array5) // [10, 6, 2, 3, 1, 8, 5, 4, 7, 9]


Source Code

Source code for this post could be found here on GitHub

Monday, June 25, 2018

Swift Defer Statement

defer keyword is used for declaring a block of code that will wait and will be executed just before exit from current scope (function, closure, loop, etc. ).  The block of code inside defer statement is guaranteed to be executed regardless of how we exit from current scope: normally, from a guard, or because of error.

Simple example
func testDefer1() {
    defer {
        print("Defer step 3")
    }
    print("Normal step 1")
    print("Normal step 2")
}

testDefer1()

//Normal step 1
//Normal step 2
//Defer step 3

defer scope


As mentioned before, defer statement will be executed before exit from current scope. So, if scope that contains defer statement is inside other scope, than defer will be executed on exit from inner scope.

defer scope example
func testDefer2() {
    print("Normal step 1")
    customFunc()
    print("Normal step 2")
}

func customFunc() {
    print("Custom step 1")
    print("Custom step 2")
    defer {
        print("Custom defer step 3")
    }
}

testDefer2()

//Normal step 1
//Custom step 1
//Custom step 2
//Custom defer step 3
//Normal step 2

As we can see here:
  1. Firstly will be printed strings from begin of outer scope
  2. Secondly will be printed strings from inner scope
  3. Thirdly will be printed strings from defer that in inner scope (just before exit from inner scope)
  4. Fourthly will be printed strings from end of outer scope

defer inside for loop


If we will use defer inside, for example, 'for loop', defer statement will be executed before end of each iteration of the loop.

Example of usage defer inside for loop
func testDefer3() {
    for i in 1...5 {
        print("Normal step iteration begins \(i)")
        defer {
            print("Defer step \(i)")
        }
        print("Normal step iteration ends \(i)")
    }
}

testDefer3()

//Normal step iteration begins 1
//Normal step iteration ends 1
//Defer step 1
//Normal step iteration begins 2
//Normal step iteration ends 2
//Defer step 2
//Normal step iteration begins 3
//Normal step iteration ends 3
//Defer step 3
//Normal step iteration begins 4
//Normal step iteration ends 4
//Defer step 4
//Normal step iteration begins 5
//Normal step iteration ends 5
//Defer step 5

Multiple defer statements


If there are multiple defer statements inside scope they will be executed in reverse order. Their execution will follow LIFO pattern - Last In First Out.

Multiple defer example
func testMultipleDefer() {
    print("Normal step 1")
    defer {
        print("Defer step 1")
    }
    defer {
        print("Defer step 2")
    }
    defer {
        print("Defer step 3")
    }
    print("Normal step 2")
}

testMultipleDefer()

//Normal step 1
//Normal step 2
//Defer step 3
//Defer step 2
//Defer step 1

As you can see, order of execution is reversed to order of adding to scope.


defer limitations


There are some limitations for using defer statement. You cannot exit from body of defer statement with following things:
  1. call return
  2. call break
  3. throw an error


Where we can use defer in Real Life Applications


The defer statement can be very useful when we want to clean up before exit from scope (for example, close connections to database or file, release unneeded resources), even if an error is thrown. For example, when we work with file and open a file to write to, we will want to make sure that we close opened file, even if there is an error happened while we work with file. 

Example of usage defer statement when working with file
func writeToFile(filename: String, text: String) throws {
    if let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
        
        let path = directory.appendingPathComponent(filename).absoluteString
        
        guard let file = FileHandle(forUpdatingAtPath: path) else {
            print("File open failed")
            throw FileError.fileNotFound(reason: "File not found")
        }
        
        defer {
            print("Close file...")
            file.closeFile()
        }
        
        let fileURL = directory.appendingPathComponent(filename)
        
        do {
            try text.write(to: fileURL, atomically: false, encoding: .utf8)
        }
        catch {
            throw FileError.cannotWriteToFile(reason: "Cannot write to file")
        }
    }
}
In code snippet above, we close file before exit from function. And we close file in defer statement to make sure that we close file at any case, even if error was being thrown.


Source Code


Source code for this article could be found here on GitHub

Saturday, June 2, 2018

Coding Interview. String Compression Challenge

Task description


Given a string, write a function that accepts this string as input and returns compressed string. Algorithm of compression is following: every sequence of the same character should be replaced with that character followed by the number of repetitions. If the compressed string is longer than the original string, then function should return the original string.

Algorithm for this challenge also known as Run Length Encoding.

Examples of input and output

  • a becomes a (because a1 is not shorter than a)
  • aa becomes aa (because a2 is not shorter than aa)
  • aaa becomes a3
  • abc becomes abc (because a1b1c1 is not shorter than abc)
  • aabbbdcccc becomes a2b3d1c4
  • aaabbbccc becomes a3b3c3
  • aabbbcccdeee becomes a2b3c3d1e3

Swift Implementation Prerequisites


In Swift we cannot get character of string by it's integer index. If we try to do this we will have an error. 
let test = "aaabbbbdcccee"

for i in 0..<(test.count - 1) {
    let ch = test[i] // error
}

'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion

For getting character we must calculate "String.Index" value first.  
for i in 0..<(test.count - 1) {
    let index = test.index(test.startIndex, offsetBy: i)
    let character = test[index]
    print(character)
}

For simplifying this we can make subscript method for String type and get character by index.
let test = "aaabbbbdcccee"

extension String {
    
    subscript (i: Int) -> Character {
        let index = self.index(self.startIndex, offsetBy: i)
        let character = self[index]
        return character
    }
}

print(test[0]) // a
print(test[3]) // b
print(test[test.count - 1]) // e

Algorithm

  1. Create variables 
    • result for compressed string
    • sum for counting each character
  2. For loop from 0 to n-2 (where n = length of string, n - 2 because we will compare current and next characters)
    • Compare current and next characters
      • If they are equal add 1 to sum
      • Else append current character and sum to result and reset sum to 0
  3. Append to result last character and sum (because in for loop we update result only in case of characters are changed).
  4. Compare lengths of initial and compressed strings and return one with less length.

Swift Implementation

let test1 = "abbbc"
let test2 = "aaa"
let test3 = "abc"
let test4 = "aabbbcccdeee"

func compress(_ str: String) -> String {
    var result = ""
    var sum = 1
    for i in 0..<(str.count - 1) {
        if (str[i] == str[i + 1]) {
            sum += 1
        } else {
            result += "\(str[i])\(sum)"
            sum = 1
        }
    }
    result += "\(str[str.count - 1])\(sum)"
    return result.count < str.count ? result : str
}

print(compress(test1)) // abbbc -> abbbc
print(compress(test2)) // aaa -> a3
print(compress(test3)) // abc -> abc
print(compress(test4)) // aabbbcccdeee -> a2b3c3d1e3

We can improve algorithm
  1. Initially assign 0 to sum
  2. For loop from from 0 to n-1
  3. Increase sum by 1 in each iteration
  4. In each iteration check if it is the end of string or current and next characters are different. If Condition is true than append current character and sum to result and reset sum to 0.
func compress_v2(_ str: String) -> String {
    var result = ""
    var sum = 0
    for i in 0..<str.count {
        sum += 1
        if (i + 1 == str.count) || (str[i] != str[i + 1]) {
            result += "\(str[i])\(sum)"
            sum = 0
        }
    }
    return result.count < str.count ? result : str
}

More "Swifty" Implementation


But there could be more "swifty" solution without using string index. We can use for each loop for string characters.

Algorithm
  1. Create three variables: 
    • currentCharacter - optional variable for current character
    • sum - counter for for each character
    • result - compressed string
  2. For loop for each character in string
    • If character is equal to currentCharacter then add 1 to sum
    • Else do following
      • Check that currentCharacter has value and if it has then add this value and sum to result
      • Save character into currentCharacter
      • Reset sum to 1
  3. After loop finished, append currentCharacter and sum to the result string. (This step can be easily forgotten, because in for loop we only modify result string in case of character changes.)
  4. Compare lengths of initial and compressed strings and return one with less length.
func compress_v3(_ str: String) -> String {
    var currentCharacter: Character?
    var sum = 0
    var result = ""
    for ch in str {
        if ch == currentCharacter {
            sum += 1
        } else {
            if let current = currentCharacter {
                result.append("\(current)\(sum)")
            }
            currentCharacter = ch
            sum = 1
        }
    }
    if let current = currentCharacter {
        result.append("\(current)\(sum)")
    }
    return result.count < str.count ? result : str
}

print(compress_v3(test1)) // abbbc -> abbbc
print(compress_v3(test2)) // aaa -> a3
print(compress_v3(test3)) // abc -> abc
print(compress_v3(test4)) // aabbbcccdeee -> a2b3c3d1e3

Complexity


Because we have only one for loop - space complexity of this algorithm will be linear - O(n).

Source Code 


Source code of from this post could be found here on GitHub