Tips: Array Tricks

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

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.