Skip to content

Instantly share code, notes, and snippets.

@rainypixels
Last active November 22, 2022 00:46
Show Gist options
  • Star 75 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save rainypixels/ae8c3b0021acc7673416 to your computer and use it in GitHub Desktop.
Save rainypixels/ae8c3b0021acc7673416 to your computer and use it in GitHub Desktop.
/*
Swift Programming Language Guide
"A Swift Tour" Solutions
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-XID_1
These are the solutions to all the "experiments" in the pre-release Swift Programming Guide
(released on the same day Apple announced Swift). A couple of things worth noting:
1. Swift syntax, e.g. array declarations, has changed since I releasd these. So this code will
probably cause some errors when you paste it into a playground. Should be easy enough to fix
(and maybe a good exercise unto itself? :) )
2. As some of the commenters have pointed out, I messed up a few solutions. So, please be sure
to check the comments for the correct answers.
*/
import Cocoa
// Create a constant with an explicit type of Float and a value of 4.
let valueOfFour: Float = 4.0
// Try removing the conversion to String from the last line. What error do you get?
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
// let widthLabel = label + width
// Use \() to include a floating-point calculation in a string and to include someone’s name in a greeting.
let height:Float = 68
let name = "Yoshi"
let myHeight = "\(name)'s height is \(height + 0.5) inches"
// Change optionalName to nil. What greeting do you get? Add an else clause that sets a different greeting if optionalName is nil.
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
teamScore
var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = nil
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
} else {
greeting = "Hello, Yoshi"
}
greeting
// Try removing the default case. What error do you get?
let vegetable = "red pepper"
switch vegetable {
case "celery":
let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
let vegetableComment = "That would make a good tea sandwich."
case let x where x.hasSuffix("pepper"):
let vegetableComment = "Is it a spicy \(x)?"
default:
let vegetableComment = "Everything tastes good in soup."
}
// Add another variable to keep track of which kind of number was the largest, as well as what that largest number was.
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var largestKind = ""
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
largestKind = kind
}
}
}
largest
largestKind
// Remove the day parameter. Add a parameter to include today’s lunch special in the greeting.
func greet(name: String, special: String) -> String {
return "Hello \(name)! Today's special is \(special)."
}
greet("Bob", "Meatloaf")
// Write a function that calculates the average of its arguments.
func average (numbers:Int...) -> Float {
var sum = 0
var total = 0
for n in numbers {
sum += n
total++
}
return Float(sum / total)
}
average(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// Rewrite the closure to return zero for all odd numbers.
var numbers = [20, 19, 7, 12]
numbers.map({
(number: Int) -> Int in
var result = 0
if number % 2 == 0 {
result = 3 * number
}
return result
})
// Add a constant property with let, and add another method that takes an argument.
class Shape {
var numberOfSides = 0
let numberOfDimensions = 3
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
func isNDimensional(dimensions:Int) -> Bool {
var response = false
if (numberOfDimensions == dimensions) {
response = true
}
return response
}
}
var shape = Shape()
shape.isNDimensional(3)
// Make another subclass of NamedShape called Circle that takes a radius and a name as arguments to its initializer. Implement an area and a describe method on the Circle class.
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
class Circle: NamedShape {
var radius: Double = 0;
init(radius: Double, name: String) {
self.radius = radius;
super.init(name:name)
}
func area() -> Double {
return M_PI * radius * radius
}
override func simpleDescription() -> String {
return "A circle with radius of \(radius)"
}
}
let test1 = Circle(radius: 9.9, name: "my test circle")
test1.area()
test1.simpleDescription()
// Write a function that compares two Rank values by comparing their raw values.
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.toRaw())
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.toRaw()
func isSameRank (first: Rank, second: Rank) -> Bool {
return first.toRaw() == second.toRaw()
}
isSameRank (Rank.Ace, Rank.Queen)
isSameRank (Rank.Two, Rank.Two)
// Add a color method to Suit that returns “black” for spades and clubs, and returns “red” for hearts and diamonds.
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
func color () -> String {
switch self {
case .Spades:
return "black"
case .Clubs:
return "black"
case .Hearts:
return "red"
case .Diamonds:
return "red"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
hearts.color()
Suit.Spades.color()
// Add a method to Card that creates a full deck of cards, with one card of each combination of rank and suit.
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
func createDeck() -> Card[] {
var deck = Array (count: 52, repeatedValue: Card(rank: .Ace, suit: .Spades))
var suits = [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs];
var counter = 0;
for i in 1...13 {
for suit in suits {
deck[counter++] = Card (rank: Rank.fromRaw(i)!, suit: suit)
}
}
return deck
}
func printDeck (deck: Card[]) {
for card in deck {
println (card.simpleDescription())
}
}
let deck = createDeck()
printDeck(deck)
// Add a third case to ServerResponse and to the switch.
enum ServerResponse {
case Result(String, String, String)
case Error(String)
}
let success = ServerResponse.Result("6:00 am", "8:09 pm", "14:09h")
let failure = ServerResponse.Error("Out of cheese.")
switch success {
case let .Result(sunrise, sunset, daylight):
let serverResponse = "Sunrise is at \(sunrise), sunset is at \(sunset), and total daylight is \(daylight)."
case let .Error(error):
let serverResponse = "Failure... \(error)"
}
// Write an enumeration that conforms to this protocol.
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
enum SimpleEnum: ExampleProtocol {
case A, B, AA, BB
var simpleDescription: String {
get {
switch self {
case .A:
return "A simple enum: A"
case .B:
return "A simple enum: B"
case .AA:
return "A simple enum: AA"
case .BB:
return "A simple enum: BB"
}
}
}
mutating func adjust() {
switch self {
case .A:
self = A
case .B:
self = B
case .AA:
self = A
case .BB:
self = B
}
}
}
var c = SimpleEnum.AA
c.simpleDescription
c.adjust()
c.simpleDescription
// Write an extension for the Double type that adds an absoluteValue property.
extension Double {
var abs: Double {
get {
return fabs(self)
}
}
}
var myDouble = -17.8
myDouble.abs
// Modify the anyCommonElements function to make a function that returns an array of the elements that any two sequences have in common.
func commonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Array<T.GeneratorType.Element> {
var result = Array<T.GeneratorType.Element>()
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
result.append(lhsItem)
}
}
}
return result
}
var result = commonElements([1, 2, 3], [3, 2])
println(result)
@zorion79
Copy link

zorion79 commented Jun 5, 2014

Can you help me?
I don't understand that part of code

extension Double {
    var abs: Double {
        get {
            return fabs(self)
        }
    }
}

What is mean "fabs"?

@gdefaveri
Copy link

@zorion79

extension Double {
    var abs: Double {
    get {
        if self < 0 {
            return -self
        } else {
            return self
        }
    }
    }
}

@zorion79
Copy link

zorion79 commented Jun 5, 2014

@gdefaverl thank you

@loganfuller
Copy link

"Modify the anyCommonElements function to make a function..."

As for the final experiment, it seems that they are asking you to write a function generator rather than to simply modify the existing function:

func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> () -> ((T, U) -> Array<T.GeneratorType.Element>) {
    func generatedFunction(lhs: T, rhs: U) -> Array<T.GeneratorType.Element> {
        var commonElements = Array<T.GeneratorType.Element>()
        for lhsItem in lhs {
            for rhsItem in rhs {
                if lhsItem == rhsItem {
                    commonElements.append(lhsItem)
                }
            }
        }
        return commonElements
    }
    return generatedFunction
}
let arrayUnion: ((Int[], Int[]) -> Int[]) = anyCommonElements()
arrayUnion([1, 2, 3], [3, 2])

@Seaton63
Copy link

Seaton63 commented Jun 8, 2014

Why doesn't line 284 - 'printDeck(deck)' produce anything in the sidebar?

@skallen
Copy link

skallen commented Sep 26, 2014

"Add a method to Card that creates a full deck of cards, with one card of each combination of rank and suit."

The exercise asks to add a method to the Card structure, not an external function. Just sayin' ...

@Jean-Batiste
Copy link

I think you misread the actual Experiment description : "Add a third case to ServerResponse and to the switch." A third case is not a third string to the same case. Here is my own little 2 ¢ as a solution to the guided tour.

enum ServerResponse {
case Result(String, String)
case Error(String)
case Wait(String, String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")
let wait = ServerResponse.Wait("Wait a second.", "Mmmh, see you tommorrow.")

switch success {
case let .Result(sunrise, sunset):
let serverResponse = "Sunrise is at \(sunrise), sunset is at \(sunset), and total daylight is \(daylight)."
case let .Error(error):
let serverResponse = "Failure... \(error)"
case let .Wait(wait1, wait2) :
let serverResponse = "Server working. \(wait1) Server glutted. \(wait2)"
}

You may easily test the code by replacing switch success with switch wait and see the third case popping out…

Hope you liked it :)

Thanks a lot for the solutions. I've tiptoed into c language, and am now trying myself to OOP with swift and c++. It's sobering to hear that my li'le c knowledge is precisely what swift inteds to get rid of :(. But I'll get through it. Thanks again for your help.

@Jean-Batiste
Copy link

Wow. Last Experiment solution makes Playground crash…

@rainypixels
Copy link
Author

@Jean-Batiste

I think you misread the actual Experiment description : "Add a third case to ServerResponse and to the switch." A third case is not a third string to the same case. Here is my own little 2 ¢ as a solution to the guided tour.

Yep. Nice catch, and thanks for the solution.

I've tiptoed into c language, and am now trying myself to OOP with swift and c++. It's sobering to hear that my li'le c knowledge is precisely what swift inteds to get rid of :(. But I'll get through it. Thanks again for your help.

If it's any consolation, I picked up Objective C just a year ago (had done C/C++ years ago). I felt a little disappointed initially that I'd invested so much in Obj-C. But after spending a few months in Swift, it's pretty clear that Obj-C is here to stay for a while, and I'm glad I'm fluent in both. That said, I'm completely sold on Swift at this point. I think you'll be surprised at how useful your C knowledge is going to prove.

@rainypixels
Copy link
Author

@skallen Haha, my bad. Read it in a haste.

@rainypixels
Copy link
Author

@oganfuller You're totally right. Thanks for posting the solution!

@awoodall
Copy link

awoodall commented Nov 2, 2014

for the "Write a function that calculates the average of its arguments." experiment should you declare 'sum' and 'total' as Floats individually to return the decimal point as well?

// Write a function that calculates the average of its arguments.
func average (numbers:Int...) -> Float {
    var sum = 0
    var total = 0

    for n in numbers {
        sum += n
        total++
    }
    return Float(sum) / Float(total)
}
average(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

@StanislavCekunov
Copy link

My Suggestion for
// Add a color method to Suit that returns “black” for spades and clubs, and returns “red” for hearts and diamonds.

   func color () -> String {
        switch self {
        case .Spades, .Clubs:
            return "black"
        case .Hearts, .Diamonds:
            return "red"
        }
    }

Just a little bit cleaner ;)

@deinfrank
Copy link

I was wondering about the difference between structs and classes. To help me understand, what if we had created the deck of cards from instances of a class called Card rather than copies of a structure called Card? Thank you so much for all of your work on helping students of swift!

@jtransue
Copy link

jtransue commented Jan 1, 2016

I'm having trouble getting the average exercise to work and the solution code generates the same problem. Even when it should return a float, it's returning integers. Here's the code and an example

func average (numbers:Int...) -> Float {
    var sum = 0
    var total = 0

    for n in numbers {
        sum += n
        total++
    }

    return Float(sum / total)
}

average(2,3)
// Should give 2.5, but gives 2

The average of 2 and 3 is 2.5, but even though the code looks like it should return 2.5, it doesn't in a playground on Xcode 7.2.

@jtransue
Copy link

jtransue commented Jan 1, 2016

I found that awoodall's suggestion is what the solution code needs to change to work. You need to make both the numerator and denominators floats, so to work it has to be:

return Float(sum) / Float(total)

I don't completely understand why this is its behavior adding (sum) or incrementing(total) an Int isn't going to give a float so it's only when you do the division that you get a float.

@jpromano
Copy link

On the last experiment, had to make several mods to get it to work with latest Xcode/Swift Playground v 7.2.1

Playground Swift code:

//: Playground - noun: a place where people can play

import UIKit

func anyCommonElements <T, U
    where
    T: SequenceType, U: SequenceType,
    T.Generator.Element: Equatable,
    T.Generator.Element == U.Generator.Element>
    (lhs: T, rhs: U)
    -> [T.Generator.Element]
{
    var  returnValue: [T.Generator.Element] = []
       for lhsItem in lhs {
       for rhsItem in rhs {
            if lhsItem == rhsItem {
                returnValue.append(lhsItem)
            }
        }
    }
    return returnValue
}

let commonNumberList = anyCommonElements([1, 2, 3,4,5,6,7,8], rhs:[2,3,9,14,8,21])
print("common Numbers = \(commonNumberList)")

let commonStringList = anyCommonElements(["a","b","c"],rhs:["d","e","f","c","b"])
print("common Strings = \(commonStringList)")
anyCommonElements([1, 2, 3], rhs:[3])
anyCommonElements([1, 2, 3], rhs:[9,7,0])
print(anyCommonElements(["bird", "fish", "dog"], rhs:["birdog", "cat", "dog", "fish"]))

Playground Debug Window Output:________________
common Numbers = [2, 3, 8]
common Strings = ["b", "c"]
["fish", "dog"]

@johnanderpalma
Copy link

This is my approach to write a function that calculates the average of its arguments:

func average (numbers:Float...) -> Float {
    var sum: Float = 0
    for number in numbers {
        sum += number
    }
    return sum / Float(numbers.count)
}
average(2,3) //gives 2,5

@gallaugher
Copy link

Thanks for the crib sheet. I think the info below may help correct/improve the results:

On Average: awoodall above is right. The average code needs:
return Float(sum) / Float(total)
sum & total in the above function are defined as ints, so their divided result will yield an int, even if there should be a remainder.
For example, if you change the call parameters to:
average(numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 11)
return Float (sum/total)
returns 5

return Float(sum) / Float(total)
correctly returns 5.6

ALSO: If you want to update for Swift 3.0, it looks like the ++ operator has been eliminated in Swift 3, so change:
total++
to
total += 1

John's approach is more elegant, but veers from simple mod of the existing code.

@jamgro2434
Copy link

@johnanderpalma This was my solution as well. But the people finding this page may not be aware of .count
allowing for fractions in the array as well as the average is a good practice. Assuming this would be for an accounting app, how would you format the result to the nearest hundredth? Also, how would you format to the nearest hundredth without rounding up?
example: 2.551947 returning 2.55
example: 2.555947 returning 2.55

@jamgro2434
Copy link

jamgro2434 commented Oct 5, 2016

Personally I was hoping to use the already provided sumOf function to calculate the sum for the avgOf function. How might one achieve this?

something to the effect of:
avgOf(sumOf(numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10))

@sgtbilge
Copy link

sgtbilge commented Nov 11, 2016

// This is the solution I came up with for the Swift 3 version of the last exercise.

func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element]
    where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
        var result = Array<T.Iterator.Element>()
        for lhsItem in lhs {
            for rhsItem in rhs {
                if lhsItem == rhsItem {
                    result.append(lhsItem)
                }
            }
        }
        return result
}

// Thanks to jpromano (see solution from Feb 21) for the test case design.
let commonNumberList = anyCommonElements([7,9,22,4,17,100], [4,9,33,2,99])
print("common Numbers = \(commonNumberList)")

let commonStringList = anyCommonElements(["a","b","c"],["d","e","f","c","b"])
print("common Strings = \(commonStringList)")

@OSHenry
Copy link

OSHenry commented Feb 26, 2017

// Modify the anyCommonElements function to make a function that returns an array of the elements that any two sequences have in common.
func commonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Array<T.GeneratorType.Element> {
var result = Array<T.GeneratorType.Element>()

for lhsItem in lhs {
    for rhsItem in rhs {
        if lhsItem == rhsItem {
            result.append(lhsItem)
        }
    }
}
return result

}
var result = commonElements([1, 2, 3], [3, 2])
println(result)

Anyone please expain the last experiment???? I cannot understand generics part.

@Atomica-1
Copy link

Atomica-1 commented Apr 19, 2018

For some reason I keep getting \n showing up in the output section after seemingly random outputs.
for example: On second page Line 14: print(teamScore) - Output: 11\n

@yugaego
Copy link

yugaego commented Jul 6, 2018

My version of the last (swift 4.2 tour) experiment:

    func findCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element]
            where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
            var result: [T.Iterator.Element] = []
            for lhsItem in lhs {
                for rhsItem in rhs {
                    if lhsItem == rhsItem && !result.contains(lhsItem) {
                          result.append(lhsItem)
                    }
                }
            }
            return result
    }
findCommonElements([1, 3, 5, 24, 7], [7, 8, 7, 1])

@maahd
Copy link

maahd commented Oct 29, 2018

Line 221 and 222 need to get changed to

isSameRank (Rank.Ace, Rank.Queen)
isSameRank (Rank.Two, Rank.Two)

because of compiler error:

error: Enumerations and Structures.xcplaygroundpage:26:11: error: missing argument labels 'first:second:' in call isSameRank(Rank.jack, Rank.queen)

Tried to create pull request but failed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment