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:
- Do I need ordered values?
- Do I need unique values
- Do I need access directly to any value?
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..
The Whole Code
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)
Leave a Reply