iOS Training from beginner to advanced
Of the most underrated collection types is sets. Sets are an unordered collection with unique values. Let’s take a look at what you can do with sets.
Download the exercise files and you’ll find I created playground with a Struct called Pizza. I’ve made two pizzas for you. Currently, this is all arrays, but does it have to be arrays? Ask yourself three questions:
If you need ordered values and direct access, you’ll want an array. If you want unique values and don’t care about order or access, you’ll want a set. A Pizza is a good example of where a set works well. An ingredient is an ingredient. There is no good reason to list it twice, and it also has no particular order for toppings. I don’t need to access only one ingredient. That’s a set. Sets are stored and accessed more eifficiently than array or dictionaries, so if you can use a set, do so.
Lets convert this struct to sets. For the two constants on top, I add Set and the compiler will implicitly make this a set of strings. For cheese and toppings, I have to get more explicit.
var cheeses: Set<String>
var toppings: Set<String>
I added the type of the set in angle brackets. Run what you got and it still works. The pizzas below still compile.
You can enumerate a set using for. For example:
for cheese in quattroFormaggi.cheeses{
print(cheese)
}
You are not guaranteed the order however. If I want them sorted, I can use the sorted method
for cheese in quattroFormaggi.cheeses.sorted(){
print(cheese)
}
The core of sets is membership testing. I can check for the existence of something easily.
chicago.toppings.contains("Sausage")
returns true
quattroFormaggi.toppings.contains("Sausage")
Return false.
I can look for a bigger set too. I have a set of toppings here. I can check it against one of my pizzas.
margheritaDoc.toppings.isSubset(of: toppings)
That comes out false. I can find the missing ingredients quickly.
margheritaDoc.toppings.subtracting(toppings)
And I find I have whole tomatoes instead of crushed here.
Are any authentic cheeses also toppings? I can use an intersection to check that.
margheritaDoc.toppings.intersection(margheritaDoc.authenticCheese)
That gives me one case. If I want true or false I can use isEmpty. To look for the empty set.
margheritaDoc.toppings.intersection(margheritaDoc.authenticCheese).isEmpty
What if I want to check against two pizzas. I can union the pizzas and check that against the list.
let cheeses = quattroFormaggi.cheeses.union(margheritaDoc.cheeses)
cheeses.intersection(quattroFormaggi.authenticCheese)
So What of the two lists are excluded?
cheeses.symmetricDifference(quattroFormaggi.authenticCheese)
I for one would consider all that Authentic.
In this simple example you can see that if you don’t care about order and have unique values, Sets may be a an efficient way of storing data..
You can download this Swift playground from GitHub here: Tips_08_01_Sets_End
struct Pizza{ let authenticCheese: Set = ["Bufalo","Fior de late","Gorgonzola","Mozzarella","Parmigiano"] let authenticIngredients: Set = ["Basil","Peppers","Tomatoes", "Basil", "Oregano"] enum Crust{ case thin,thick,pan,lavosh,potPie } var crust : Crust var cheeses: Set<String> var toppings: Set<String> } let margherita = Pizza(crust: .thin, cheeses: ["Mozzarella"], toppings: ["Basil","Tomatoes","Parmigiano","Oil"]) let margheritaDoc = Pizza(crust: .thin, cheeses: ["Bufala"], toppings: ["Basil","Tomatoes","Parmigiano","Oil"]) let chicago = Pizza(crust: .pan, cheeses: ["Mozzarella"], toppings: ["Pizza Sauce","Sausage"]) let quattroFormaggi = Pizza(crust: .thin, cheeses: ["Fontina","Gorgonzola","Mozzarella","Parmigiano"], toppings: ["Crushed Tomatoes","Basil","Oil"]) for cheese in quattroFormaggi.cheeses.sorted(){ print(cheese) } let toppings: Set = ["Crushed Tomatoes","Basil","Oil","Chicken","BBQ Sauce","Red Onions","Parmigiano", "Peppernoi","Prociutto","Pineapple","Canadian Bacon"] chicago.toppings.contains("Sausage") quattroFormaggi.toppings.contains("Sausage") margheritaDoc.toppings.isSubset(of: toppings) margheritaDoc.toppings.subtracting(toppings) margheritaDoc.toppings.intersection(margheritaDoc.authenticCheese).isEmpty let cheeses = quattroFormaggi.cheeses.union(margheritaDoc.cheeses) cheeses.intersection(quattroFormaggi.authenticCheese) cheeses.symmetricDifference(quattroFormaggi.authenticCheese)