Gold Challenge (my simple way)

import Cocoa

func padding(amount: Int) -> String {
var paddingString = ""
for _ in 0 …< amount {
paddingString += " "
}
return paddingString
}

protocol TabularDataSource {
var numberOfRows: Int { get }
var numberOfColumns: Int { get }

func labelForRow(row: Int) -> String
func labelForColumn(column: Int) -> String

func itemForRow(row: Int, column: Int) -> String // my modification for the Gold Challenge (instead of: "func itemForRow(row: Int, column: Int) -> Int")

}

func printTable(dataSource: protocol<TabularDataSource, CustomStringConvertible>) {

print("Table: \(dataSource.description)")

let rowLabels = (0 ..< dataSource.numberOfRows).map { dataSource.labelForRow($0) }

let columnLabels = (0 ..< dataSource.numberOfColumns).map {
    dataSource.labelForColumn($0)
}

let rowLabelWidths = rowLabels.map({ $0.characters.count })
guard let maxRowLabelWidth = rowLabelWidths.maxElement() else {
    return
}

/* ------------------ my add for the Silver Challenge ------------------ */


let columnLabelWidths = columnLabels.map({ $0.characters.count })

var personAge = [String]()
var personYearsOfExperience = [String]()

for i in 0 ..< dataSource.numberOfColumns {
    for j in 0 ..< dataSource.numberOfRows {
        let intItem = dataSource.itemForRow(j, column: i)
        if i == 0 {
            personAge.append(intItem)
        }
        if i == 1 {
            personYearsOfExperience.append(intItem)
        }
    }
}

let personAgeWidths = personAge.map({ String($0).characters.count })
guard let maxPersonAgeWidth = personAgeWidths.maxElement() else {
    return
}

let personYearsOfExperienceWidths = personYearsOfExperience.map({ String($0).characters.count })
guard let maxPersonYearsOfExperienceWidth = personYearsOfExperienceWidths.maxElement() else {
    return
}

let maxFirstColumn = max(maxPersonAgeWidth, columnLabelWidths[0])
let maxSecondColumn = max(maxPersonYearsOfExperienceWidth, columnLabelWidths[1])

/* --------------------------------------------------------------------- */

var firstRow: String = padding(maxRowLabelWidth) + " |"

var columnWidths = [Int]()

for columnLabel in columnLabels {
    
/* ------------------ my add for the Silver Challenge ------------------ */
    
    let paddingAmount0 = maxFirstColumn - columnLabelWidths[0]
    let paddingAmount1 = maxSecondColumn - columnLabelWidths[1]
    var columnHeader: String?
    if columnLabel == columnLabels[0] {
        columnHeader = padding(paddingAmount0) + " \(columnLabel) |"
    }
    if columnLabel == columnLabels[1] {
       columnHeader = padding(paddingAmount1) + " \(columnLabel) |"
    }
    
    firstRow += columnHeader!
    columnWidths.append(columnHeader!.characters.count)
    
/* --------------------------------------------------------------------- */
    
}

print(firstRow)

for i in 0 ..< dataSource.numberOfRows {
    let paddingAmount = maxRowLabelWidth - rowLabelWidths[i]
    var out = rowLabels[i] + padding(paddingAmount) + " |"
    
    for j in 0 ..< dataSource.numberOfColumns {
        let item = dataSource.itemForRow(i, column: j)
        
        let itemString = " \(item) |"
        let paddingAmount = columnWidths[j] - itemString.characters.count
        out += padding(paddingAmount) + itemString
    }
    print(out)
}

}

/* --------------------- my add for the Gold Challenge ---------------------- */

struct Book {
let title: String
let author: String
let averageReviewOnAmazon: String
}

struct BookCollection: TabularDataSource, CustomStringConvertible {
let name: String
var books = Book

var description: String {
    return "BookCollection \(name)"
}

init(name: String) {
    self.name = name
}

mutating func addTitle(title: Book) {
    books.append(title)
}

var numberOfRows: Int {
    return books.count
}
var numberOfColumns: Int {
    return 2
}
func labelForRow(row: Int) -> String {
    return books[row].title
}
func labelForColumn(column: Int) -> String {
    switch column {
    case 0: return "Title"
    case 1: return "Average review on Amazon"
    default: fatalError("Invalid column!")
    }
}
func itemForRow(row: Int, column: Int) -> String {
    let book = books[row]
    switch column {
    case 0:
        return book.author
    case 1:
        return book.averageReviewOnAmazon
    default:
        fatalError("Invalid column!")
    }
}

}

var bookCollection = BookCollection(name: “of Rolfino”)
bookCollection.addTitle(Book(title: “Jonathan Livingston Seagul”, author: “Richard Bach”, averageReviewOnAmazon: “Very nice book”))
bookCollection.addTitle(Book(title: “Biplane”, author: “R. Bach”, averageReviewOnAmazon: “Good Book”))
bookCollection.addTitle(Book(title: “Uno, nessuno e centomila”, author: “Pirandello”, averageReviewOnAmazon: “Pretty good”))

printTable(bookCollection)

/* -------------------------------------------------------------------------- */