Swift (Set Data-Structure) Basics, With Practical Example : Pizza Cooking
5 (1)

Click to rate this post!
[Total: 1 Average: 5]
Unsplash.com

Swift provides three main collection types, Arrays, Sets, and Dictionaries..

A set is a collection of unique and unordered data, simply, the data elements has no order. and it’s guaranteed to have non-duplicate values.

You use a set instead of an array when you need to test efficiently for membership and you aren’t concerned with the order of the elements in the collection, or when you need to ensure that each element appears only once in a collection.

Swift Source Code.

Asking about the importance of sets is like asking about the importance of the alphabet, set theory is the basic to so much math, any practical application of anything in math is normally an application of set theory.

a Venn diagram, showing the intersection of two sets (Wikipedia)

The basic operations on sets are Union, Intersection, Difference, isSubset, isSuperset.. but swift provide a lot of functions, you can perform set operations with another set, an array, or any other sequence type 🧐, you can use higher order functions like map and filter… etc.

func filter
func isSubset
func isSuperset
func isDisjoint
func subtracting
func isStrictSuperset
func isStrictSubset
func intersection
func map<T>
func dropFirst
func dropLast
func drop
func prefix
func suffix
func split
func firstIndex
func shuffled<T>
func shuffled
func flatMap<ElementOfResult>
func forEach
func first
func withContiguousStorageIfAvailable<R>
func enumerated
func min
func max
func starts<PossiblePrefix>
func elementsEqual<OtherSequence>
func lexicographicallyPrecedes<OtherSequence>
func contains
func allSatisfy
func reduce<Result>
func reversed
func flatMap<SegmentOfResult>
func compactMap<ElementOfResult>
func sorted
func index
func formIndex
func distance
func randomElement<T>
func randomElement
func makeIterator
func isSubset<S>
func isStrictSubset<S>
func isSuperset<S>
func isStrictSuperset<S>
func isDisjoint<S>
func union<S>
func subtracting<S>
func intersection<S>
func symmetricDifference<S>
func hash
func joined
func joined<Separator>
func encode
func mapValues<T>
func compactMapValues<T>
func merging<S>
func merging

let’s start with a simple example

// Data
var myKitchenItemsSet: Set = ["Mozzarella","Mushrooms","Pineapples","Tomatoes","Mushrooms","Garlic"]
let shoppingListItemsSet: Set = ["Olives", "Tomatoes","Sourdough"]
let pizzaIngredientsSet: Set = ["Sourdough","Mozzarella","Mushrooms","Tomatoes","Olives"]

// the order of union operator is not important, even union1 and union2 show up differnlt when printing!
let union1 = myKitchenItemsSet.union(shoppingListItemsSet)
let union2 = shoppingListItemsSet.union(myKitchenItemsSet)

// union1 and union2 show up differently when printed, but keep in mind that they are equal

print("union1",union1)
print("union2",union2)
print("areUnionsEqual",(union1 == union2))

let itemsNeeded = shoppingListItemsSet.subtracting(myKitchenItemsSet)
print("What I need to buy:",itemsNeeded)

// Buy the needed elements
myKitchenItemsSet.formUnion(itemsNeeded)

let canMakePizza = pizzaIngredientsSet.isSubset(of: myKitchenItemsSet)
print("canMakePizza",canMakePizza)

Defining a set is straightforward, you can explicitly define the type to be a Set, notice how you can’t have multiple types directly, you can’t mix integers with strings for example, in the example the type was inferred though.

Next we created two unions to proof that the order of the union has no value, it’s like addition, even though the union sets get printed with random order in the terminal.

Then we used Subtraction to look up the items that we need to have on the shopping list, in other words, remove items already in the kitchen even if they are in the pizza recipe.

We can add the items needed into my kitchen items, notice that how duplicate items are ignored, lastly we check if the kitchen items “has” all the items in the pizza recipe.

Say you want to make a pizza for Justin Bieber?


var pizzaIngredientsForJustinSet: Set = ["Sourdough","Mozzarella","Tomatoes","Olives","Amanita phalloides"]

print("can I make Pizza for the Justin?",pizzaIngredientsForJustinSet.isSubset(of: myKitchenItemsSet))

myKitchenItemsSet.insert("Rotten Mushrooms")
myKitchenItemsSet.insert("Amanita phalloides")

print("can I make Pizza for the Justin Bieber?",pizzaIngredientsForJustinSet.isSubset(of: myKitchenItemsSet))

Yes, this will not work until you add “Amanita phalloides” 👍

Bridging between Set and NSSet

You can bridge between Set and NSSet using the as operator, For bridging to be possible, the Element type of a set must be a class, or a type that bridges to a Foundation type.

Swift Source Code.

Performance

Sets are in general faster to process, but due to their restriction of non-repeated values, and having no order, they are not often used.

Swift Bitwise Operators (with a couple of practical examples)
5 (4)

Click to rate this post!
[Total: 4 Average: 5]

Bitwise operators are rarely used in everyday swift programming
⚠️ : not to be confused by Logical Operators like “&&” and “||”

It’s mainly used to perform operations on individual bits,  they are extremely useful and used in FlagsGraphicsNetworkingEncryption

OperatorDescription
Binary AND
|    Binary OR
^   Binary XOR
~    Binary One’s Complement
<<   Binary Shift Left
>>    Binary Shift Right
Swift Bitwise Operators



First, a refresher on the truth table of XOR, it gives True if both A and B are Different

ABResult
TRUETRUEFALSE
TRUEFALSETRUE
FALSETRUETRUE
FALSEFALSEFALSE
XOR Truth Table


The basic code to represent integers as bits, and each operator and it’s result … 🧐

extension Int {
    
    var binaryDescription: String {
        var binaryString = ""
        var internalNumber = self
        for _ in (1...self.bitWidth) {
            binaryString.insert(contentsOf: "\(internalNumber & 1)", at: binaryString.startIndex)
            internalNumber >>= 1
        }
        return "0b " + binaryString
    }
    
}

func bitwise_example() {
    
    let x1 = 0x1
    let x2 = 0x2

    print("x1\t", x1.binaryDescription )
    print("x2\t", x2.binaryDescription )
    
    let binary_and = (x1 & x2)
    let binary_or = (x1 | x2)
    let binary_xor = (x1 ^ x2)
    let binary_complement = (~x1)
    let binary_shiftL = (x1 << 1)
    let binary_shiftR = (x1 >> 1)

    print("&\t",  binary_and.binaryDescription )
    print("|\t", binary_or.binaryDescription )
    
    print("^\t", binary_xor.binaryDescription )
    print("~\t", binary_complement.binaryDescription )
    print("<<\t", binary_shiftL.binaryDescription )
    print(">>\t", binary_shiftR.binaryDescription )
    
}

Output

x1	 0b 0000000000000000000000000000000000000000000000000000000000000001
x2	 0b 0000000000000000000000000000000000000000000000000000000000000010
&	 0b 0000000000000000000000000000000000000000000000000000000000000000
|	 0b 0000000000000000000000000000000000000000000000000000000000000011
^	 0b 0000000000000000000000000000000000000000000000000000000000000011
~	 0b 1111111111111111111111111111111111111111111111111111111111111110
<<	 0b 0000000000000000000000000000000000000000000000000000000000000010
>>	 0b 0000000000000000000000000000000000000000000000000000000000000000

Real Life Usage for them:

1- Color Format Conversion
Most probably, you would have such an extension in your boilerplate iOS app, it converts HEX colors into UIColor.

extension UIColor {
   convenience init(red: Int, green: Int, blue: Int) {
       assert(red >= 0 && red <= 255, "Invalid red component")
       assert(green >= 0 && green <= 255, "Invalid green component")
       assert(blue >= 0 && blue <= 255, "Invalid blue component")

       self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
   }

   convenience init(rgb: Int) {
       self.init(
           red: (rgb >> 16) & 0xFF,
           green: (rgb >> 8) & 0xFF,
           blue: rgb & 0xFF
       )
   }
}

2- Quick & Dirty hashing

let a = 4012
let b = 8102
let c = 9101

func dirtyHash(a: Int, b: Int, c: Int) -> Int{
    return ( a ^ b ^ c ^ 9999)
}

3- Base64 Encoding

Base64 encoding converts a series of 8 bit bytes into 6 bit character lookup indexes. (SHIFT)ing, (AND)ing, (OR)ing, (NOT)ing are used for implementing the bit operations necessary for Base64 encode/decode.

4- Checking if a number is Odd/Even.

func isEven(number: Int) -> Bool{
    return ((number & 0x1) == 0)
}

func isOdd(number: Int) -> Bool{
    return ((number & 0x1) > 0)
}

5- Solving Problems efficiently and in a performant way.
Write a program to swap the value of two variable.

Using temporary variable

c =  a; a = b; b = c; 

Without using temporary variable

a = a+b; b = a-b; a = a-b; 

Using bitwise operator

a = a^b; b = a^b; a = a^b; 

6- Calculating valid network addresses for a subnet

7- Calculating Permission in Role-based access control systems, RBAC.

8- Calculating Inverse Square Root very fastly
http://h14s.p5r.org/2012/09/0x5f3759df.html

Also:

Some people use bitwise operators to handle multiple error code together, each bit can hold a separate value.

N-bitmap can be a really cool and compact data structure.