Chapter 3. Collecting and Controling: Going Loopy for Data

image

You already know about expressions, operators, variables, constants, and types in Swift. It’s time to consolidate and build on that knowledge and explore some more advanced Swift data structures and operators: collections and control flow. In this chapter, we’re going to talk about putting collections of data into variables and constants, and how to structure data, manipulate data, and operate on data using control flow statements. We’ll be looking at other ways to collect and structure data later in the book, but for now let’s get started with arrays, sets, and dictionaries.

Sorting pizzas

image

Meet the Swift Pizzeria, the fastest pizza place in town.

image

The Chef, who is pretty grumpy at the best of times, wants to sort his pizzas alphabetically using Swift (he figures that since his pizza shop is named Swift, he should learn the language).

image

He’s facing some issues though. Can you help Swift Pizzeria sort their pizzas?

Swift has a range of special types that can store collections of things. Unsurprisingly, these are called collection types.

Note

The name says it all, really!

There’s three main collection types you can use to store collections in Swift: arrays, sets, and dictionarys. They all have differences, and knowing when to use the right one is a fundamental skill of Swift programming.

The quickest way to store a list of pizzas in a collection and then sort them alphabetically is an array, but you’ll come back to that. Before you can help the chef, you need to think about each of the collection types and what they can do.

Swift Collection Types

The Swift types you’ve used so far allow you to store individual pieces of data, of different types (for the most part). For example, String lets you store strings, Int lets you store integers, Bool lets you store boolean values, and so on.

Swift’s collection types allow you to store multiple pieces of data.

A collection type makes storing collections of things much easier.

image

Arrays are ordered, and every element has a value of the same type, is automatically numbered with an index, starting from 0. This means you can access individual values using the indices.

image

Sets are unordered, and every element has a value of the same type. There no index value for sets, so you need to access them using features of the Set, or by iterating through the whole set.

Each value can only be stored in a Set once.

image

Dictionaries are an unordered collection of keys and values. Every key is the same type, and every value is the same type. A value can be accessed using its key, just like indices in Arrays. The keys can be different types to the values.

Collecting values in an array

The first collection type we’re going to look at is an array. An array is collection of things, of the same type, that has a specific order. You can create an array simply, like this array of strings representing potential names for a cat:

image

An array is an ordered collection of values of the same type.

Or you could create an array like this, like this variable array of integers:

image

Arrays number the values they hold, starting from 0. So the array we just created would look like this:

image

We can add things to variable arrays in a variety of ways, including appending:

image

We can add things to variable arrays in a variety of ways, including appending:

image

You can also remove elements:

      numbers.remove(at: 3)

And change the value of specific elements:

      numbers[2] = 307

How big is that array, exactly? Is it empty?

You knew exactly how big the arrays we’ve worked with so far were, but what if you need to work with an array that you don’t know the length of in advance?

Imagine you’ve been asked to do something with an array, named ingredients, that contains the ingredients you need for a specific pizza. It’s been created somewhere else, so you don’t know how many elements are in it.

In this case, we’ll take a peek behind the curtain. Here’s the array being created:

image

Every collection type in Swift has a property available: count. count lets you get the number of elements in the collection, like this:

image
      print("There are (ingredients.count)
                          ingredients in this pizza.")

You can also do other useful things, like check if the array is empty:

image
      print(ingredients.isEmpty)

There’s also some convenience methods that let you get the minimum and maximum elements of an array:

      print(ingredients.max())


      print(ingredients.min())

Collecting values in a set

The second collection type that we’re going to use is the set. Sets are similar to arrays, and must contain solely one type, but sets are unordered, and there can only be one of each distinct value in a set.

You can create a set like this:

      var evenNumbers = Set([2, 4, 6, 8])

Or like this:

      var oddNumbers: Set = [1,3,5,7]

Sets are useful when you need to make sure each item only appears once.

There are other ways to create sets, and we’ll cover them later in the book.

You can insert items into sets, just like with an array:

image

And likewise, you can easily remove elements (even if they don’t exist in the set you can still ask for it to be removed):

image

Collecting values in a dictionary

The final collection type we’re going to use right now is a dictionary. As you might be able to intuit from the name, a dictionary collects things by mapping one thing, to another (just like a real-world dictionary maps a word to a definition). Like sets, dictionairies in Swift are unordered.

If you wanted to create a dictionary that represented some people who played a board game, and the score they got, you could do it like this:

image

Or like this, where you tell the Swift compiler explicitly which types you’d like the keys and values to be:

image

We can also create an empty dictionary like this, but we have specify the types in advance, because (obviously) the compiler can’t figure that out without any values present:

      var scores: [String: Int] = [:]
image

Reading a value from a dictionary is a little strange, compared to what we’ve done so far.

To read a value from a dicitionary, you can simply use the key:

      print(scores["Paris"]!)

The exclamation mark afterwards is used to directly access the value of the key, and we’ll come back to that syntax a little bit later, in the next chapter, when we use optionals.

You can also add new values or change existing ones in the dictionary, like this:

      scores.updateValue(17, forKey: "Bob")

Or like this:

      scores["Josh"] = 4
image

The three main collection types are the array, set, and dictionary.

But Swift has also a few more tricks up its sleeve. There is a concept of a generic collection type, which we’ll get to much later, where you can create your own collection types, but there’s also the humble tuple.

Tuples let you store multiple values in a single variable or constant, but without the overhead of being (for example) an array.

Note

Tuples are perfect for when you need a very specific collection of values where each item has an exact position or name.

Tuples

A tuple can store as many values as you like, as long as the amount of them and type of them is defined up front. For example, you could use a tuple to represent coordinates, like x and y, and store them in one variable:

image

Tuples can have names for each component or have no names at all. You can update or modify tuples without using the names for the components, as long as the types of the values match:

image

You can also always access the contents of tuples using integers, starting from 0:

image

Everyone needs a good alias

When you’re working with the various data types in Swift, one of the ways you can make your code self-documenting is by using type aliases. A type alias, basically, lets you give a new name to an existing type.

Let’s take a look at a quick example: a simple, one-way, celcius to fahrenheit temperature convertor, written without any type aliases:

image

While this is a very small, simple piece of code, it can be made easier to follow using type aliases:

image

Control flow statements

When you’re coding in Swift (and other programming languages, naturally), it’s often useful to be able to do something repeatedly or do something under certain conditions. These two concepts, broadly, are often called control flow.

There’s lots of tools in your control flow toolbox, and they all work a little differently, and all have their place.

image

There are no hard rules.

You can use all of these control flow statements in a variety of situations. There’s no single rule that tells you when to use what, but it will usually be relatively obvious.

If statements are best for executing some code only if a certain condition is true.

Switch statements are useful in the same context, but if you have lots of possible different case, depending on the conditions.

For loops, for-in loops, while loops, and repeat-while loops allow you to repeatedly execute some code based on certain conditions.

You’ll find uses for all of these control flow statements as you code more.

image

If statements

If statements allow you to do something under certain conditions. They allow you to execute some specific code if certain conditions are met. If statements, broadly, are part of a group of concepts known as conditionals.

If you have a Bool named userLovesPizza and you wanted to use it to determine whether you should give the user a pizza, based on whether they love pizza or not, you could use an if statement.

image

The if statement can be combined with else in order to provide more options.

image

The conditional in an if statement must be a Boolean expression. This means it must evaluate to either true, or false. If the expression is true, the code inside the if statement (between the two { }) is executed.

Switch statements

You often have to think about a lot of possibilities when you’re creating conditionals with if statements. Going back to the pizza shop we were helping with the if statements, imagine how unwiedly things could get if we also wanted to send a special message with each type of pizza? We’ll check if a string variable contains a certain type of pizza, and display a message based on that pizza. We’ll need to use a new operator, the equal to operator, to check.

We might end up with something that looks like this:

image
image

A switch statement often serves you better if you need to execute some different code depending on the value of a variable or constant..

Lots of if statements becomes unreadable, and very inelegant, fast. A switch statement lets you switch which bits of code get run, based on the values of variables or constants that you want to switch on.

A switch statement can have multiple clauses, and is not simply limited to testing for equality or comparing. We’ll come back to this later.

Going back to our pizza shop, we can rewrite the potential giant series of if statements as a nice, clean switch statement:

image

Building a Switch statement

So, if we (for some reason) wanted to check if a number was 9, 42, 47, or 317, we could use a switch statement:

image

A switch statement is easier to maintain in the long term, and makes for more readable code..

We’ll come back to switch statements both later in book (when we look at enumerations). But, in general, if you have more than a handful of things you’re checking for in a large block of if-else statements, then you might want to consider switch statement.

image

Range operators

In addition to the mathematical operators you’ve already seen, and the assignment operator, Swift has several other useful operators, including a selection of range operators. Range operators are shortcuts for expressing a range of values. They are particularly useful for loops and other control-flow statements:

These both represent the range 1, 2, 3, 4:

image

The closed range operator defines a range that runs from the value on the left side of the operator to the value on the right side.

The half-open range operator defines a range that runs from the value on the left side of the operator to the value immediately before the value on the right side.

There’s also a one-sided range operator that lets you consider a range that continues as far as it can in one direction. For example, the following constants defines a range that starts at 5 and continues infinitely, and a range that goes from an infinitely negative number to 100, respectively:

image

We can then check if the constanst contain a certain value:

image

More complex switch statements

Say you need to help a school write some code that prints out a text representation of a student’s final grade. The school grades on a system of Fail (0 to 49 points), Pass (50 to 59), Credit (60 to 69), Distinction (70 to 79), and High Distinction (80 to 89). You could do this with a bunch of if statements, but it wouldn’t look very nice.

Consider a switch statement:

image
image

But the switch statement has more tricks up its its sleeve. We’ll look at one final trick here, before we come back to switches later in the book.

Imagine if you want to switch on a number, and check whether it’s an odd numer or an even number. You can do it like this:

image

Getting repeatative with loops

Swift has two major loop statements you can use: for (and for-in) loops, for running some code a certain number of times, or iterating through every item in a collection type, and while (and do-while) loops, for running some code over and over again until something becomes true, or false.

You can also put loops inside other loops if you want.

image

Building a For Loop

Let’s unpack this, and write some code that displays the numbers from 1 to 10, using a for loop:

image

The ... you see in the range is called the closed-range operator. This operator lets you define a range that runs from the value specified before the operator to the value specified after the operator, including both of those values. So the range 1...5 is 1, 2, 3, 4, 5.

image

The for-in loop makes it easy to iterate over the items in an array.

Programming is thirsty work, so let’s pretend we’re running a café, and we’re using an Array of Strings called drinks to keep track of which drinks are still available.

If we want to iterate through that array, and display a message to let people know what they can order, we can use a for-in loop.

image

Swift doesn’t know what a single drink is called.

We can use a word that makes it easier for a human to understand what’s going on.

If the only purpose of your loop is to simply iterate through some sort of data structure, you might be able to use for each instead:

image

Building a while loop

Let’s unpack this, and write a while loop that, while a number is less than 100, multiplies the number by 2:

A while loop is particularly useful when you’re not sure how many iterations the loop will go through until it’s started.

image

Building a repeat-while loop

Let’s write the same loop we wrote over the page, for the while loop, but using repeat-while instead:

image

Solving the pizza sorting problem

image
var pizzaHawaiian = "Hawaiian"
var pizzaCheese = "Cheese"
var pizzaMargherita = "Margherita"
var pizzaMeatlovers = "Meatlovers"
var pizzaVegetarian = "Vegetarian"
var pizzaProsciutto = "Prosciutto"
var pizzaVegan = "Vegan"

There are no Dumb Questions

Q: Where are the semicolons? I thought programming was meant to be full of semicolons!

A: Swift doesn’t end lines with semicolons. If it makes you feel more comfortable, you can do it anyway. It’s still valid, it’s just not necessary!.

Q: I thought Swift had something called “protocols” instead of classes? When are we learning those? What about classes?

A: Swift does have something called “protocols”, and we promise that we’ll get to it. We’ll also get to classes very soon. Swift has more than one way to structure a program, and both classes and protocols offer useful paths forward. Be patient, and we’ll get there.

Q: How do I run my code on an iPhone or iPad? I bought this book so I could learn to make iOS apps and get filthy rich.

A: We’ll explain everything you need to know to use your Swift knowledge to make iOS apps much, much later in the book. We make no promises about getting rich, but we do promise that you’ll know how to build iOS apps by the end. Again, be patient.

Q: Why would I ever use a constant when I could just make everything a variable in case it needs to change?

A: Swift places a much greater emphasis on using constants than other programming languages do. It can help, a lot, with making your program safer and more stable by only using variables for values that you expect to change. Additionally, by telling the Swift compiler that your values with be constants, the compiler can make our programs faster by performing certain optimizations for us.

Q: Why can’t I change the type of a value after I’ve assigned it? Other languages can do this.

A: Swift is a strongly typed language. It puts a lot of emphasis on the way type system works, and encourages you to learn it. You cannot change the type of a variable after you’ve created it. You can create a new variable and cast the type to something new if you need to.

Q: I don’t really understand the difference between enumerations and structures and classes. What’s the point of having three similar things?

A: It’s hard to convey without a little more experience under your belt. Trust us to point you in the right direction. In a few more chapters you’ll be equipped with the gut-feeling to pick which one you need. We promise.

Q: Optionals seem really useful. Why don’t other programming languages seem to have those?

A: That’s a great question. We have no idea.

Q: So are variables and constants also types?

A: No, variables and constants are named locations to store data. The data in a variable or constant has a type, so the variable or constant has a type, but it in itself is not a type.

Q: What if I need to store some data that Swift doesn’t have a type for?

A: Great question. We’ll be looking at ways you can create your own types later on in the book.

Q: What about the Collection Types? Can I make my own Collection Type too?

A: Yes, we’ll get back to this in a chapter or three, as it requires some advance Swift features. But the answer is yes: you can make your own Collection types that are just as capable as the provided three (arrays, sets, dictionaries).

Q: What do I do if I need to create a variable, but don’t know what type to set it to in advance?

A: Another great question! You might have noticed that in our code so far, sometimes we specify a type in the expression that creates a variable, and sometimes we don’t. Swift’s type system is able to infer types, or use a provided type annotation.

Q: Switch statements in other languages I’ve looked at don’t seem very powerful, and I never used them. Swift seems to have considerably more powerful switch statements. What’s the deal?

A: You’re right. Swift’s switch statement is considerably more capable than most other language’s. Switch statements are super useful, and Swift has a really good implementation of them.

image

Phew, that’s a lot of Swift!

You’re only three chapters into your Swift journey, but you’ve already done so much. You’ve learned about the building blocks of Swift, and how to create a Swift Playround and build programs out of operators, expressions, variables, constants, types, collections, and control flow. Phew.

image

Have a break, tackle some of the exercises remaining in this chapter, and get some rest so you’re refreshed to march onwards!

We recommend starting with the a review of your knowledge so far, through the bullet points over the page, and tackling the crossword puzzle on the next page. Don’t skip them!

Repeating your Swift knowledge helps solidify what you’ve learned.

Swift Code Magnets

image Exercise

A Swift program is all scrambled up on the fridge. Can you reconstruct the code snippets to make a working Swift program that produces the output listed over the page? The code uses concepts you’ve looked at in detail, as well as a few that you haven’t.

image
image

Images Pool Puzzle

Your job is to take lines of code from the pool and place them into the blank lines in the playground. You may not use the same line more than once, and you won’t need to use all the lines Your goal is to make the code that will generate the output shown below, given the starting variables:

image
Note

each thing from the pool can only be used once!

image

image Exercise

Images BE the Swift compiler

Each of the Swift code snippets on this page represents a complete playground. Your job is to play Swift compiler, and determine whether each of these will run or not. If they will not compile, how would you fix them? What’s wrong with them if they won’t work?.

A

let dogsAge = 10
let dogsName = "Trevor"

print("My dog's name is (dogsName) and
they are (dogsAge) years old.")

dogsAge = dogsAge + 1

B

var number = 10

for i in 1...number {
    print(number*92.7)
}

C

var bestNumbers: Set = [7, 42, 109, 53, 12, 17]

bestNumbers.remove(7)
bestNumbers.remove(109)
bestNumbers.remove(242)

bestNumbers.insert(907)
bestNumbers.insert(1002)
bestNumbers.insert(42)

image Swiftcross

It’s time to test your brain. Gently.

This is just a normal crossword, but all the solutions are from concepts we covered in this chapter. How much did you pay attention?

image

Across

4. Related functionality and values

5. An ordered collection of values of the same type

7. A named piece of data that can never change

9. A named piece of repeatable code

13. Mixing values with a string

14. Checking what’s inside an optional

15. This statement helps you run different code depending on the value of a variable (amongst other things)

16. A type that can store positive or negative

17. A way to execute some code over and over again

18. Something to check, combine, or change a value

Down

1. A group of related values

2. A decimal number

3. A place to code Swift without the clutter of an IDE

6. A type that can store some words. Or a word.

7. A way to store groups of values

8. An unordered collection of values of the same type

10. A named piece of data that can change later

11. A collection of values mapped to other values

12. Representing a value, as well as the potential absence of a value

13. A whole number

image Exercise Solution

Code Magnets

image
class Dog {
    var name: String
    var color: DogColor
    var age: Int

    init(name: String, color: DogColor, age: Int) {
        self.name = name
        self.color = color
        self.age = age
    }
}
enum DogColor {
    case red
    case brown
    case black
}
var fido = Dog(name: "Fido", color: .brown, age: 7)
var bruce = Dog(name: "Bruce", color: .black, age: 4)
var moose = Dog(name: "Moose", color: .red, age: 11)
var pack: [Dog] = [fido, bruce]

func addDogToPack(dog: Dog) {
    pack.append(dog)
    print("(dog.name) (aged (dog.age)) has joined the pack.")
}
func listDogsInPack() {
    print("The pack is:")
    print("--")
    for dog in pack {
        print(dog.name)
    }
    print("--")
}
listDogsInPack()
addDogToPack(dog: moose)
listDogsInPack()

Images Pool Puzzle

image Exercise Solution

var todaysWeather = "Windy"
var temperature = 35
var message = "Today's Weather"

switch todaysWeather {
case "Sunny":
    message = "It's a lovely sunny day!"
case "Windy":
    message = "Strap your hat on. It's windy!"
case "Raining":
    message = "Pack your umbrella!"
case "Snow":
    message = "Brr! There's snow in the air!"
default:
    message = "It's a day, you know?"
}
if(temperature > 65) {
    message += " And it's not cold out there."
} else if(temperature < 35) {
    message += " And it's chilly out there."
} else {
    message += " And it's not cold or hot!"
}
print(message)

Images BE the Swift compiler

A

The code will error because we’re trying to modify a constant (dogsAge). We need to change the dogsAge constant to a variable for this to work.

B

This works fine, exactly as it is.

C

The code will error when you try and multiply a double (92.7) by an integer (number). Additionally, we’re not using the i that’s counting up inside the loop at all.

image Swiftcross

image Exercise Solution

image

REQUIRED LEFT-HAND PAGE FOR ENDING CHAPTER. INTENTIONALLY BLANK.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.160.216