iOS Development tips weekly is a series you can find at the Lynda.com and LinkedIn Learning libraries. The first week of a week’s tip will be available for free. After that, you will need a subscription to get access to it. Click the image at left to view. You’ll find an amended transcript below.
For some tips, I’d like to get back to basics, looking at some of the things we use everyday, but may not use all of those features. One of those is the often used array. So I’d like to show you some of the power methods you may not be using. Start with a blank playground in Xcode or iPad. I’ll use the iPad today. You can also download the starter file from Github.
Arrays are ordered collections of a single type. For example, these are a literal arrays of integers and strings
var array = [1,3,5,7,5,3,2,7,5,4,3] var toppings = ["Pepperoni","Cheese","Sausage","Veggie","Pineapple"]
I’ll make a struct
struct Pizza{ var topping:String var size:Double }
and made an array of pizzas, adding elements to the array with the +=
var pizzas = [Pizza(topping: "Cheese", size: 10.0)] pizzas += Pizza(topping: "Mushroom", size: 16.0)] pizzas += [Pizza(topping: "Pineapple", size:12.0)]
The topics I’d like to cover are sorting and searching arrays, which you might not have used due to something known as predicates.
Sorting Arrays can be easy as using the sorted method.
array.sorted() toppings.sorted()
Run the code. You can see in the debugging panel the array sorts.
And the same for the toppings:
But what if you wanted to sort backwards or by some other criterion? That’s what predicates are for.
You use the array.sorted(by:)
method. You’ll see this uses a special closure returning a boolean value known as a predicate. You’ll create a condition in the closure which tells Xcode when to swap values. By sorting one greater than two we can reverse the sort
array.sorted { (one, two) -> Bool in one > two }
Run This. Checking the debugger, you get the reverse
Predicates handle another, equally important situation. When working with classes and structs for types, you may want to sort on a certain property. Let’s sort by size in Pizzas
pizzas.sorted { (one, two) -> Bool in one.size < two.size }
And tap the viewer to see the pizzas sorted.
Since the only shows the structs, I’ll drill down to see the elements
Predicates play an even bigger role in finding elements in the array. There are three ways of finding elements. One is finding the index from an element value. A simple, non-predicate version is this:
array.index(of: 42) toppings.index(of: "Cheese")
You can use a predicate here too. For example finding the index of a 12 inch pizza.
pizzas.index(where: { (pizza) -> Bool in pizza.size >= 12.0 })
Index finds the first occurrence of the item.
There are two pizzas that satisfy this predicate, the 12 inch Pineapple and the 16 inch Mushroom, but we get the 16-inch mushroom only.
Another type of find is the contains
method. contains
returns a boolean value if one or more of the elements have the value. Again there is a simple version for simple types.
array.contains(42)
And one with a predicate for more complex cases includes structs and classes.
pizzas.contains { (pizza) -> Bool in pizza.topping == "Pineapple" }
Like index
, first
uses a predicate to return the element that satisfies the predicate.
pizzas.first(where: { (pizza) -> Bool in pizza.size >= 12.0 })
This returns the object, which might be what you are looking for.
You might need one specific value from the object, like this:
pizzas.first(where: { (pizza) -> Bool in pizza.size >= 12.0 })?.topping
Which returns the topping of a twelve inch pizza.
The last find is the filter
, Which returns multiple occurrences of the predicates. For the integer array I can do this:
array.filter( { (int) -> Bool in int >= 7 })
And I find everything seven or greater.
You can put any code you want in the closure. For our final example, lets make a common compound case where I’ll use two finds. I’ll filter the results to be Pizza toppings found in the pizza topping list. I’ll start with a filter
pizzas.filter( { (pizza) -> Bool in })
Then add a contains for toppings inside the closure
pizzas.filter( { (pizza) -> Bool in toppings.contains(where: { (string) -> Bool in string == pizza.topping }) })
I have the pizzas that are on my toppings list.
Sort and find functions are often very necessary for arrays as a data structure. While you can write your own sorts, you’ll find plenty of uses for the built in versions that provide quite a lot of power.
The Whole Code
Here is the entire playground. You can also download the finished playground on Github. For those of you not familiar withe the //:
comment notation, this creates markup and formatting in playgrounds, and makes the text read-only on an iPad after you save the playground.
//:# Array Predicate Play //: A example of using predicates with arrays import UIKit //: Arrays are ordered collections of a single type. I'll set up a few arrays for us to use. var array = [1,3,5,7,5,42,3,2,7,5,4,3] var toppings = ["Pepperoni","Cheese","Sausage","Veggie","Pineapple"] struct Pizza{ var topping:String var size:Double } var pizzas = [Pizza(topping: "Cheese", size: 10.0)] pizzas += [Pizza(topping: "Mushroom", size: 16.0)] pizzas += [Pizza(topping: "Pineapple", size:12.0)] //:## Sorting elements //: The `sorted` method sorts an array of a simple type in ascending order. For decending order or complex types, you need a predicate. array.sorted() toppings.sorted() array.sorted { (one, two) -> Bool in one > two } pizzas.sorted { (one, two) -> Bool in one.size < two.size } //:## Finding Elements //: Finding elelemnts also relies heavily on predicates. //: Finding the index array.index(of: 42) toppings.index(of: "Cheese") pizzas.index { (pizza) -> Bool in pizza.size >= 12.0 } //: Finding existence of an element array.contains(42) pizzas.contains { (pizza) -> Bool in pizza.topping == "Pineapple" } //: Finding the first occurance pizzas.first { (pizza) -> Bool in pizza.size >= 12.0 }?.topping //: Finding a collection of occurances (Filtering) array.filter { (int) -> Bool in int >= 7 } pizzas.filter { (pizza) -> Bool in toppings.contains(where: { (topping) -> Bool in topping == pizza.topping }) }
Leave a Reply