I'm really stuck on the following challenge:
The printTable(_:) function has a bug – it crashes if any of the data items are longer than the label of their column. Try changing Joe’s age to 1,000 to see this happen. Fix the bug. (For an easier version of this challenge, just make the function not crash. For a harder version, make sure all the rows and columns of the table are still aligned correctly.)
The challenge is referring to the following:
//: Playground - noun: a place where people can play
import Cocoa
protocol TabularDataSource {
var numberOfRows: Int { get }
var numberOfColumns: Int { get }
func label(forColumn column: Int) -> String
func itemFor(row: Int, column: Int) -> String
}
func printTable(dataSource: TabularDataSource & CustomStringConvertible) {
print("Table: \(dataSource.description)")
var firstRow = "|"
var columnWidths = [Int]()
for i in 0 ..< dataSource.numberOfColumns {
let columnLabel = dataSource.label(forColumn: i)
let columnHeader = " \(columnLabel) |"
firstRow += columnHeader
columnWidths.append(columnLabel.count)
}
print(firstRow)
for i in 0 ..< dataSource.numberOfRows {
var out = "|"
for j in 0 ..< dataSource.numberOfColumns {
let item = dataSource.itemFor(row: i, column: j)
let paddingNeeded = columnWidths[j] - item.characters.count //deleting "item.characters.count" makes the function not crash
let padding = repeatElement(" ",count: paddingNeeded).joined(separator: " ")
out += " \(padding)\(item) |"
}
print(out)
}
}
struct Person {
let name: String
let age: Int
let yearsOfExperience: Int
}
struct Department: TabularDataSource, CustomStringConvertible {
let name: String
var people = [Person]()
var description: String {
return "Department (\(name))"
}
init(name: String) {
self.name = name
}
mutating func add(_ person: Person) {
people.append(person)
}
var numberOfRows: Int {
return people.count
}
var numberOfColumns: Int {
return 3
}
func label (forColumn column: Int) -> String {
switch column {
case 0: return "Employee Name"
case 1: return "Age"
case 2: return "Years of Experience"
default: fatalError("Invalid column!")
}
}
func itemFor(row: Int, column: Int) -> String {
let person = people[row]
switch column {
case 0: return person.name
case 1: return String(person.age)
case 2: return String(person.yearsOfExperience)
default: fatalError("Invalid column!")
}
}
}
var department = Department(name: "Engineering")
//When you change one of these ages to "1000" the program crashes
department.add(Person(name: "Joe", age: 20, yearsOfExperience: 6))
department.add(Person(name: "Karen", age: 40, yearsOfExperience: 18))
department.add(Person(name: "Fred", age: 50, yearsOfExperience: 20))
printTable(dataSource: department)
//I found that by deleting "item.characters.count" in line 38 makes the function not crash
//However I'm struggling with the harder version of making sure all of the rows and columns are aligned correctly
I've had a hard time with the second part of the challenge and haven't made much progress. I'd appreciate some hints/suggestions to point me in the right direction