 # Chapter 10: Tuples & Enums

## Swift Programming from Scratch

The Swift Sandbox is integrated, making the exercises interactive. Read more about the book here.

## Chapter 10: Tuples & Enums #### Tuples

A tuple is a group of zero or more values represented as one value.

For example `("John", "Smith")` holds the first and last name of a person. You can access the inner values using the dot(`.`) notation followed by the index of the value:

```var person = ("John", "Smith")

var firstName = person.0 // John
var lastName = person.1 // Smith```
##### Named elements

You can name the elements from a tuple and use those names to refer to them. An element name is an identifier followed by a colon(:).

```var person = (firstName: "John", lastName: "Smith")

var firstName = person.firstName // John
var lastName = person.lastName // Smith```
##### Creating a tuple

You can declare a tuple like any other variable or constant. To initialize it you will need a another tuple or a tuple literal. A tuple literal is a list of values separated by commas between a pair of parentheses. You can use the dot notation to change the values from a tuple if it’s declared as a variable.

```var point = (0, 0)

point.0 = 10
point.1 = 15

point // (10, 15)```

Note: Tuple are value types. When you initialize a variable tuple with another one it will actually create a copy.

```var origin = (x: 0, y: 0)

var point = origin
point.x = 3
point.y = 5

print(origin) // (0, 0)
print(point) // (3, 5)```
##### Types

The type of a tuple is determined by the values it has. So `("tuple", 1, true)` will be of type `(String, Int, Bool)`. You can have tuples with any combination of zero or more types.

If the tuple has only one element then the type of that tuple is the type of the element. `(Int)` is the same as `Int`. This has a strange implication: in swift every variable or constant is a tuple.

```var number = 123

print(number) // 123
print(number.0) // 123
print(number.0.0) // 123
print(number.0.0.0) // 123
print(number.0.0.0.0.0.0.0) // 123```
##### Empty tuple

`()` is the empty tuple – it has no elements. It also represents the `Void` type.

##### Decomposing Tuples
```var person = (firstName: "John", lastName: "Smith")

var (firstName, lastName) = person

var (onlyFirstName, _) = person
var (_, onlyLastName) = person```

Note: the `_` means “I don’t care about that value”

##### Multiple assignment

You can use tuples to initialize more than one variable on a single line:

```var a = 1
var b = 2
var c = 3```

you can write:

`var (a, b, c) = (1, 2, 3)`

``````a = 1
b = 2
c = 3
``````

you can write:

``````(a, b, c) = (1, 2, 3)
``````

And yes! One line swap:

``````(a, b) = (b, a)
``````
##### Returning multiple values

You can return multiple values from a function if you set the result type to a tuple. Here is a simple example of a function that return the quotient and the remainder of the division of `a` by `b`.

```func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
return (a / b, a % b)
}

divmod(7, 3) // (2, 1)
divmod(5, 2) // (2, 1)
divmod(12, 4) // (3, 0)```

Or the named version:

```func divmod(_ a: Int, _ b:Int) -> (quotient: Int, remainder: Int) {
return (a / b, a % b)
}

divmod(7, 3) // (quotient: 2, remainder:1)
divmod(5, 2) // (quotient: 2, remainder:1)
divmod(12, 4) // (quotient: 3, remainder:0)```

#### Enums

An enumeration is a data type consisting of a set of named values, called members.

##### Defining an enumeration

You can define a new enumeration using the `enum` keyword followed by it’s name. The member values are introduced using the `case` keyword.

```enum iOSDeviceType {
case iPhone
case iWatch
}

var myDevice = iOSDeviceType.iPhone```
##### Dot syntax

If the type of an enumeration is known or can be inferred then you can use the dot syntax for members.

```// in this case the type is known
var myDevice: iOSDeviceType = .iPhone

// in this case the type can be inferred
if myDevice == .iPhone {
print("I have an iPhone!")
}```
##### Associated Values

Swift enumerations can store associated values of any type, and the value type can be different for each member. For example you might want to store a device model for the iPhone and iPad (like `"mini"` for the iPad, or `"6 Plus"`for the iPhone).

```enum iOSDeviceType {
case iPhone(String)
case iWatch
}```

You can get the associated values by using a switch statement:

```var myDevice = iOSDeviceType.iPhone("6")

switch myDevice {
case .iPhone(let model):
print("iPhone \(model)")
case .iWatch:
print("iWatch")
default:
print("not an iOS device")
}

// iPhone 6```

Note: Swift does not provide equality operators automatically for enumerations with associated values. You might be tempted to use nested switch statements in order to test equality. Don’t forget the tuple pattern!

```var myDevice = iOSDeviceType.iPhone("6")
var six = iOSDeviceType.iPhone("6")
var sixPlus = iOSDeviceType.iPhone("6 Plus")

// testing equlity with == wont work
// myDevice == six
// myDevice == sixPlus

func sameDevice(_ firstDevice: iOSDeviceType,
secondDevice: iOSDeviceType) -> Bool {
switch (firstDevice, secondDevice) {
case (.iPhone(let a), .iPhone(let b)) where a == b:
return true
return true
case (.iWatch, .iWatch):
return true
default:
return false
}
}

print(sameDevice(myDevice, six)) // true
print(sameDevice(myDevice, sixPlus)) // false
print(sameDevice(myDevice, .iWatch)) // false```
##### Raw Values

Enums can have a raw value (a primitive type – Int, String, Character, etc.) associated with each member. The raw value will be of the same type for all members and the value for each member must be unique. When integers are use they autoincrement is a value is not defined for a member.

```enum Direction: Int {
case up = 1
case down // will have the raw value 2
case left // will have the raw value 3
case right // will have the raw value 4
}```

You can use raw values to create a enumeration value.

```var direction = Direction(rawValue: 4) // .Right

print(direction) // Optional((Enum Value))```

Note: Because not all raw values have an associated member value the raw value initializer is a failable initializer. The type of `direction` is `Direction?` not `Direction`.

### 10.1 Game

You are working on a game in which your character is exploring a grid-like map. You get the original `location` of the character and the `steps` he will take.
A step `.Up` will increase the x coordinate by 1. A step `.Down` will decrease the x coordinate by 1. A step `.Right` will increase the y coordinate by 1. A step `.Left` will decrease the y coordinate by 1.
Print the final `location` of the character after all the steps have been taken.

Example 1

Input:

```var location = (x: 0, y: 0)

var steps: [Direction] = [.up, .up, .left, .down, .left]```

Output:

``````(-2, 1)
``````

[collapse]
Example 2

Input:

```var location = (x: 0, y: 0)

var steps: [Direction] = [.up, .up, .left, .down, .left, .down, .down,
.right, .right, .down, .right]```

Output:

``````(1, -2)
``````

[collapse]
Example 3

Input:

```var location = (x: 5, y: 2)

var steps: [Direction] = [.up, .right, .up, .right, .up,
.right, .down, .right]```

Output:

``````(9, 4)
``````

[collapse]
Hint 1

Use a switch statement.

[collapse]
Hint 2

Modify the `location` tuple based on what case you’re handling in the`switch` statement.

[collapse]
Solution

```enum Direction {
case up
case down
case left
case right
}

var location = (x: 0, y: 0)

var steps: [Direction] = [.up, .up, .left, .down, .left]

for step in steps {
switch step {
case .up:
location.y += 1
case .down:
location.y -= 1
case .right:
location.x += 1
case .left:
location.x -= 1
default:
break
}
}

print(location)```

[collapse]

### 10.2 Min Max

Write a function named `minmax` that takes two integers and returns both the minimum and the maximum values inside a tuple.

Example 1

Function call:

`minmax(2, 3)`

Function output:

`(2, 3)`

[collapse]
Example 2

Function call:

`minmax(5, 1)`

Function output:

`(1, 5)`

[collapse]
Example 3

Function call:

`minmax(3, 3)`

Function output:

`(3, 3)`

[collapse]
Function Definition

`func minmax(_ a: Int, _ b: Int) -> (Int, Int)`

[collapse]
Hint 1

A single comparison is enough to determine both the minimum and the maximum value.

[collapse]
Solution

```func minmax(_ a: Int, _ b: Int) -> (Int, Int) {
if a < b {
return (a, b)
} else {
return (b, a)
}
}```

[collapse]

### 10.3 Rock, Paper, Scissors

1) Define an enumeration named `HandShape` with three members: `.rock`, `.paper`, `.scissors`.
2) Define an enumeration named `MatchResult` with three members: `.win`, `.draw`, `.lose`.
3) write a function called `match` that takes two hand shapes and returns a match result. It should return the outcome for the first player (the one with the first hand shape).

This content is restricted to buyers of Online Exercise Platform.

Function Definition

`func match(_ first: HandShape, _ second: HandShape) -> MatchResult`

[collapse]
Example 1

Function call:

`match(.rock, .scissors)`

Function output:

`.win`

[collapse]
Example 2

Function call:

`match(.rock, .paper)`

Function output:

`.lose`

[collapse]
Example 3

Function call:

`match(.scissors, .scissors)`

Function output:

`.draw`

[collapse]
Hint 1

Handle the case when the hands result in a draw first.

[collapse]
Hint 2

Determine if a win has occurred.

[collapse]
Solution

```enum HandShape {
case rock
case paper
case scissors
}

enum MatchResult {
case win
case draw
case lose
}

func match(_ first: HandShape, _ second: HandShape) -> MatchResult {
if first == second {
return .draw
}

if first == .rock && second == .scissors {
return .win
}

if first == .paper && second == .rock {
return .win
}

if first == .scissors && second == .paper {
return .win
}

return .lose
}```

[collapse]

### 10.4 Fractions

You are given 2 tuples of `a`, `b` type `(Int,Int)` representing fractions. The first value in the tuple represents the numerator, the second value represents the denominator. Create a new tuple `sum` of type `(Int,Int)` that holds the sum of the fractions.

This content is restricted to buyers of Online Exercise Platform.

Example 1

Input:

```var a = (5,8)
var b = (17,9)```

Expected Value:

`sum = (181, 72)`

[collapse]
Example 2

Input:

```var a = (34,3)
var b = (11,2)```

Expected Value:

`sum = (101, 6)`

[collapse]
Hint

To add 2 fractions together you have to get them to a common denominator.

[collapse]
Solution

```var a = (5,8)
var b = (17,9)

let numerator = a.0 * b.1 + b.0 * a.1
let denominator = a.1 * b.1
var sum = (numerator, denominator)```

[collapse]

### 10.5 Money

You are given the `CoinType` enumeration which describes different coin values and `moneyArray` which has tuples`(ammount, coinType)`. Print the total value of the coins in the array.

This content is restricted to buyers of Online Exercise Platform.

Example 1

Input:

```var moneyArray:[(Int,CoinType)] = [(10,.penny),
(15,.nickle),
(3,.quarter),
(20,.penny),
(3,.dime),
(7,.quarter)]```

Output:

``````385
``````

[collapse]
Example 2

Input:

```var moneyArray:[(Int,CoinType)] = [
(2,.penny),
(3,.quarter)
]```

Output:

``````77
``````

[collapse]
Example 3

Input:

```var moneyArray:[(Int,CoinType)] = [
(5, .dime),
(2, .quarter),
(1, .nickle)
]```

Output:

``````105
``````

[collapse]
Hint

Remember that `.rawValue` gets the numeric value associated with an enum value.

[collapse]
Solution

```enum CoinType: Int {
case penny = 1
case nickle = 5
case dime = 10
case quarter = 25
}

var moneyArray:[(Int,CoinType)] = [(10,.penny),
(15,.nickle),
(3,.quarter),
(20,.penny),
(3,.dime),
(7,.quarter)]

var totalMoney = 0

for (amount, coinType) in moneyArray {
totalMoney += amount * coinType.rawValue
}

print(totalMoney)```

[collapse]

### 10.6 Counting Strings

You are given an array of strings stored in the variable `strings`. Create a new array named `countedStrings`containing values of type `(String,Int)`. Each tuple contains a string from the `strings` array followed by an integer indicating how many times it appears in the `strings` array. Each string should only appear once in the`countedStrings` array.

This content is restricted to buyers of Online Exercise Platform.

Example 1

Input:

```var strings = ["tuples", "are", "awesome", "tuples", "are", "cool",

Expected Value:

```countedStrings = [
"tuples" : 5,
"are" : 2,
"awesome" : 1,
"cool" : 1,
]```

[collapse]
Example 2

Input:

`var strings = ["hello", "world", "hello", "swift", "hello", "tuples"]`

Expected Value:

```countedStrings = [
"hello" : 3,
"world" : 1,
"swift" : 1,
"tuples" : 1
]```

[collapse]
Hint

Keep in mind that you can’t change a tuple when iterating an array using the for in syntax. You’ll have to iterate using an index.

[collapse]
Solution

```var strings = ["tuples", "are", "awesome", "tuples", "are", "cool",

var countedStrings: [(String,Int)] = []

for string in strings {

for i in 0..<countedStrings.count {
if (countedStrings[i].0 == string) {
countedStrings[i].1 += 1
}
}
let tuple = (string,1)
countedStrings.append((string,1))
}
}```

[collapse]

## Swift Programming from Scratch

Feel free to ask any questions in the comments bellow.      (4 votes, average: 4.50 out of 5) Loading...

## 6 comments for “Chapter 10: Tuples & Enums”

1. matt
January 1, 2016 at 9:30 pm

My solution. Don’t look if you don’t want to see.

Using a dictionary:

var strings = [“tuples”, “are”, “awesome”, “tuples”, “are”, “cool”, “tuples”, “tuples”, “tuples”, “shades”, “awesome”]

var countedStrings: [(String, Int)] = []

var counters: [String: Int] = [:]

for s in strings {
if let count = counters[s] {
counters[s] = count + 1
} else {
counters[s] = 1
}
}

for (key, value) in counters {
countedStrings.append((key, value))
}

print(countedStrings)

2. Duncan Rowland
November 22, 2016 at 8:51 am

Makes sense to use reduce for the coins…
print(moneyArray.reduce(0, {\$0+\$1.0*\$1.1.rawValue}))

3. Michael
November 27, 2016 at 1:19 pm

Exercise 10.3 — seems to have a problem. I had a solution very similar to the posted solution, but it says the function is not defined correctly. If I paste it in another Xcode playground and use the examples, I get the intended results. If I copy the solution code into the exercise, I get the same error message. I’m going to assume there is something wrong with this one on the platform and move on (but that kills me not to check the box!) This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe
We send about one email per week with our latest tutorials and updates
Never display this again :)