如何在 Swift 中的协议练习中对齐 table 行和列
How to align the table rows and columns within exercise on Protocols in Swift
根据练习,在标题、作者或评分长于主 column/s 中的 header 后,table 变得未对齐(更正错误后:“重复计数应该non-negative" 通过将 - 更改为 + 以实现常量 paddingNeeded)。我想保持列宽与给定列中最长的字符串一样长,并调整其他单元格中的间距。我试图在有条件的 printTable 函数中解决它,但是没有设法比较 columnLabel 和 item,因为它们处于不同的循环中。还尝试在协议中设置新功能来管理对齐。想不通,请指教。
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("Tab. 1: \(dataSource)")
var headerRow = "|"
var columnWidths = [Int]()
for ii in 0 ..< dataSource.numberOfColumns {
let columnLabel = dataSource.label(forColumn: ii)
let columnHeader = " \(columnLabel) |"
headerRow += columnHeader
columnWidths.append(columnLabel.count)
}
print(headerRow)
for ii in 0 ..< dataSource.numberOfRows {
var out = "|"
for jj in 0 ..< dataSource.numberOfColumns {
let item = dataSource.itemFor(row: ii, column: jj)
let paddingNeeded = columnWidths[jj] - item.count
let padding = repeatElement(" ", count: paddingNeeded).joined(separator: "")
out += " \(padding)\(item) |"
}
print(out)
}
}
struct Book {
let title: String
let author: String
let rating: Int
}
struct BookCollection: TabularDataSource, CustomStringConvertible {
let name: String
var books = [Book]()
var description: String {
return ("\(name) book collection")
}
init(name: String) {
self.name = name
}
mutating func add(_ book: Book) {
books.append(book)
}
var numberOfRows: Int {
return books.count
}
var numberOfColumns: Int {
return 3
}
func label(forColumn column: Int) -> String {
switch column {
case 0: return "Title"
case 1: return "Author"
case 2: return "Rating"
default: fatalError("Invalid column!")
}
}
func itemFor(row: Int, column: Int) -> String {
let book = books[row]
switch column {
case 0: return book.title
case 1: return String(book.author)
case 2: return String(book.rating)
default: fatalError("Invalid column!")
}
}
}
var bookCollection = BookCollection(name: "Fantasy")
bookCollection.add(Book(title: "Ava", author: "Reno", rating: 7))
bookCollection.add(Book(title: "Vis", author: "Luc", rating: 7))
bookCollection.add(Book(title: "Te", author: "Julo", rating: 9))
printTable(bookCollection)
您可以向数据源添加一个方法来了解列的最大长度:
protocol TabularDataSource {
func width(for column: Int) -> Int
}
实施:
func width(for column: Int) -> Int {
var labels = (0..<numberOfRows).map { itemFor(row: [=11=], column: column )}
labels.append(label(forColumn: column))
let max = labels.max(by: { [=11=].count < .count })?.count ?? 0
return max + 2 //space before/after
}
然后:
func printTable(_ dataSource: TabularDataSource & CustomStringConvertible) {
var lines = "|"
for aColumn in 0..<dataSource.numberOfColumns {
let label = dataSource.label(forColumn: aColumn)
let totalOfSpaces = dataSource.width(for: aColumn) - label.count
let spaces = repeatElement(" ", count: totalOfSpaces / 2).joined(separator: "")
let additionalSpace = totalOfSpaces % 2 == 0 ? "" : " "
lines += "\(additionalSpace)\(spaces)\(label)\(spaces)|"
}
lines += "\n"
for aRow in 0..<dataSource.numberOfRows {
lines += "|"
for aColumn in 0..<dataSource.numberOfColumns {
let label = dataSource.itemFor(row: aRow, column: aColumn)
let totalOfSpaces = dataSource.width(for: aColumn) - label.count
let additionalSpace = totalOfSpaces % 2 == 0 ? "" : " "
let spaces = repeatElement(" ", count: totalOfSpaces / 2).joined(separator: "")
lines += "\(additionalSpace)\(spaces)\(label)\(spaces)|"
}
lines += "\n"
}
print(lines)
}
可以分解为:
func printTable(_ dataSource: TabularDataSource & CustomStringConvertible) {
func text(text: String, for width: Int) -> String {
let totalOfSpaces = width - text.count
let spaces = repeatElement(" ", count: totalOfSpaces / 2).joined(separator: "")
let additionalSpace = totalOfSpaces % 2 == 0 ? "" : " "
return "\(additionalSpace)\(spaces)\(text)\(spaces)|"
}
lines = "|"
for aColumn in 0..<dataSource.numberOfColumns {
lines += text(text: dataSource.label(forColumn: aColumn), for: dataSource.width(for: aColumn))
}
var lines += "\n"
for aRow in 0..<dataSource.numberOfRows {
lines += "|"
for aColumn in 0..<dataSource.numberOfColumns {
lines += text(text: dataSource.itemFor(row: aRow, column: aColumn), for: dataSource.width(for: aColumn))
}
lines += "\n"
}
print(lines)
}
根据练习,在标题、作者或评分长于主 column/s 中的 header 后,table 变得未对齐(更正错误后:“重复计数应该non-negative" 通过将 - 更改为 + 以实现常量 paddingNeeded)。我想保持列宽与给定列中最长的字符串一样长,并调整其他单元格中的间距。我试图在有条件的 printTable 函数中解决它,但是没有设法比较 columnLabel 和 item,因为它们处于不同的循环中。还尝试在协议中设置新功能来管理对齐。想不通,请指教。
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("Tab. 1: \(dataSource)")
var headerRow = "|"
var columnWidths = [Int]()
for ii in 0 ..< dataSource.numberOfColumns {
let columnLabel = dataSource.label(forColumn: ii)
let columnHeader = " \(columnLabel) |"
headerRow += columnHeader
columnWidths.append(columnLabel.count)
}
print(headerRow)
for ii in 0 ..< dataSource.numberOfRows {
var out = "|"
for jj in 0 ..< dataSource.numberOfColumns {
let item = dataSource.itemFor(row: ii, column: jj)
let paddingNeeded = columnWidths[jj] - item.count
let padding = repeatElement(" ", count: paddingNeeded).joined(separator: "")
out += " \(padding)\(item) |"
}
print(out)
}
}
struct Book {
let title: String
let author: String
let rating: Int
}
struct BookCollection: TabularDataSource, CustomStringConvertible {
let name: String
var books = [Book]()
var description: String {
return ("\(name) book collection")
}
init(name: String) {
self.name = name
}
mutating func add(_ book: Book) {
books.append(book)
}
var numberOfRows: Int {
return books.count
}
var numberOfColumns: Int {
return 3
}
func label(forColumn column: Int) -> String {
switch column {
case 0: return "Title"
case 1: return "Author"
case 2: return "Rating"
default: fatalError("Invalid column!")
}
}
func itemFor(row: Int, column: Int) -> String {
let book = books[row]
switch column {
case 0: return book.title
case 1: return String(book.author)
case 2: return String(book.rating)
default: fatalError("Invalid column!")
}
}
}
var bookCollection = BookCollection(name: "Fantasy")
bookCollection.add(Book(title: "Ava", author: "Reno", rating: 7))
bookCollection.add(Book(title: "Vis", author: "Luc", rating: 7))
bookCollection.add(Book(title: "Te", author: "Julo", rating: 9))
printTable(bookCollection)
您可以向数据源添加一个方法来了解列的最大长度:
protocol TabularDataSource {
func width(for column: Int) -> Int
}
实施:
func width(for column: Int) -> Int {
var labels = (0..<numberOfRows).map { itemFor(row: [=11=], column: column )}
labels.append(label(forColumn: column))
let max = labels.max(by: { [=11=].count < .count })?.count ?? 0
return max + 2 //space before/after
}
然后:
func printTable(_ dataSource: TabularDataSource & CustomStringConvertible) {
var lines = "|"
for aColumn in 0..<dataSource.numberOfColumns {
let label = dataSource.label(forColumn: aColumn)
let totalOfSpaces = dataSource.width(for: aColumn) - label.count
let spaces = repeatElement(" ", count: totalOfSpaces / 2).joined(separator: "")
let additionalSpace = totalOfSpaces % 2 == 0 ? "" : " "
lines += "\(additionalSpace)\(spaces)\(label)\(spaces)|"
}
lines += "\n"
for aRow in 0..<dataSource.numberOfRows {
lines += "|"
for aColumn in 0..<dataSource.numberOfColumns {
let label = dataSource.itemFor(row: aRow, column: aColumn)
let totalOfSpaces = dataSource.width(for: aColumn) - label.count
let additionalSpace = totalOfSpaces % 2 == 0 ? "" : " "
let spaces = repeatElement(" ", count: totalOfSpaces / 2).joined(separator: "")
lines += "\(additionalSpace)\(spaces)\(label)\(spaces)|"
}
lines += "\n"
}
print(lines)
}
可以分解为:
func printTable(_ dataSource: TabularDataSource & CustomStringConvertible) {
func text(text: String, for width: Int) -> String {
let totalOfSpaces = width - text.count
let spaces = repeatElement(" ", count: totalOfSpaces / 2).joined(separator: "")
let additionalSpace = totalOfSpaces % 2 == 0 ? "" : " "
return "\(additionalSpace)\(spaces)\(text)\(spaces)|"
}
lines = "|"
for aColumn in 0..<dataSource.numberOfColumns {
lines += text(text: dataSource.label(forColumn: aColumn), for: dataSource.width(for: aColumn))
}
var lines += "\n"
for aRow in 0..<dataSource.numberOfRows {
lines += "|"
for aColumn in 0..<dataSource.numberOfColumns {
lines += text(text: dataSource.itemFor(row: aRow, column: aColumn), for: dataSource.width(for: aColumn))
}
lines += "\n"
}
print(lines)
}