-
-
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) |
extension Double {
var abs: Double {
get {
if self < 0 {
return -self
} else {
return self
}
}
}
}
@gdefaverl thank you
"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])
Why doesn't line 284 - 'printDeck(deck)' produce anything in the sidebar?
"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' ...
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.
Wow. Last Experiment solution makes Playground crash…
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.
@skallen Haha, my bad. Read it in a haste.
@oganfuller You're totally right. Thanks for posting the solution!
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)
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 ;)
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!
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.
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.
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"]
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
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.
@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
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))
// 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)")
// 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.
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
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])
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.
Can you help me?
I don't understand that part of code
What is mean "fabs"?