Scala: нарисовать таблицу для консоли
мне нужно отобразить таблицу в консоли.
мое простое решение, если вы назовете его "решением", выглядит следующим образом:
override def toString() = {
var res = "n"
var counter = 1;
res += stateDb._1 + "n"
res += " +----------------------------+n"
res += " + State Table +n"
res += " +----------------------------+n"
for (entry <- stateDb._2) {
res += " | " + counter + "t | " + entry._1 + " | " + entry._2 + " |n"
counter += 1;
}
res += " +----------------------------+n"
res += "n"
res
}
мы не должны спорить об этом
- a выглядит плохо при отображении
- B код выглядит немного испорченным
На самом деле, такой вопрос был задан для C#, но я хотел бы знать хорошее решение для Scala.
Итак, что такое (хороший/хороший/простой/любой) способ рисовать такой стол в Scala к консоли?
-------------------------------------------------------------------------
| Column 1 | Column 2 | Column 3 | Column 4 |
-------------------------------------------------------------------------
| | | | |
| | | | |
| | | | |
-------------------------------------------------------------------------
3 ответов
Я вытащил из моего текущего проекта:
object Tabulator {
def format(table: Seq[Seq[Any]]) = table match {
case Seq() => ""
case _ =>
val sizes = for (row <- table) yield (for (cell <- row) yield if (cell == null) 0 else cell.toString.length)
val colSizes = for (col <- sizes.transpose) yield col.max
val rows = for (row <- table) yield formatRow(row, colSizes)
formatRows(rowSeparator(colSizes), rows)
}
def formatRows(rowSeparator: String, rows: Seq[String]): String = (
rowSeparator ::
rows.head ::
rowSeparator ::
rows.tail.toList :::
rowSeparator ::
List()).mkString("\n")
def formatRow(row: Seq[Any], colSizes: Seq[Int]) = {
val cells = (for ((item, size) <- row.zip(colSizes)) yield if (size == 0) "" else ("%" + size + "s").format(item))
cells.mkString("|", "|", "|")
}
def rowSeparator(colSizes: Seq[Int]) = colSizes map { "-" * _ } mkString("+", "+", "+")
}
scala> Tabulator.format(List(List("head1", "head2", "head3"), List("one", "two", "three"), List("four", "five", "six")))
res1: java.lang.String =
+-----+-----+-----+
|head1|head2|head3|
+-----+-----+-----+
| one| two|three|
| four| five| six|
+-----+-----+-----+
маркируем его. Я бы начал с создания нескольких объектов и классов case, чтобы вы создали токенизированный список, который можно использовать для отображения:
sealed trait TableTokens{
val width: Int
}
case class Entry(value: String) extends TableTokens{
val width = value.length
}
case object LineBreak extends TableTokens{
val width = 0
}
case object Div extends TableTokens{
val width = 1
}
таким образом, вы можете сформировать определенные ограничения с каким-то объектом строки:
case class Row(contents: List[TableTokens]) extends TableTokens{
val width = contents.foldLeft(0)((x,y) => x = y.width)
}
затем вы можете проверить constraits и тому подобное в неизменную моду. Возможно, создание методов добавления таблиц и выравнивания...
case class Table(contents: List[TableTokens])
это означает, что вы могли бы несколько различных вариантов таблиц, где ваш стиль отличается от вашей структуры, a la HTML и CSS.
тонна спасибо за код табулятора!
существует модификация для Искра табличная печать набора данных.
Я имею в виду, что вы можете распечатать содержимое фрейма данных или вытащить результирующий набор, например
Tabulator(hiveContext.sql("SELECT * FROM stat"))
Tabulator(hiveContext.sql("SELECT * FROM stat").take(20))
второй будет без заголовка, конечно, для реализации DF вы можете установить, сколько строк нужно вытащить из фрейма данных Spark для печати, и вам нужен заголовок или нет.
/**
* Tabular representation of Spark dataset.
* Usage:
* 1. Import source to spark-shell:
* spark-shell.cmd --master local[2] --packages com.databricks:spark-csv_2.10:1.3.0 -i /path/to/Tabulator.scala
* 2. Tabulator usage:
* import org.apache.spark.sql.hive.HiveContext
* val hiveContext = new HiveContext(sc)
* val stat = hiveContext.read.format("com.databricks.spark.csv").option("header", "true").option("inferSchema", "true").option("delimiter", "\t").load("D:\data\stats-belablotski.tsv")
* stat.registerTempTable("stat")
* Tabulator(hiveContext.sql("SELECT * FROM stat").take(20))
* Tabulator(hiveContext.sql("SELECT * FROM stat"))
*/
object Tabulator {
def format(table: Seq[Seq[Any]], isHeaderNeeded: Boolean) : String = table match {
case Seq() => ""
case _ =>
val sizes = for (row <- table) yield (for (cell <- row) yield if (cell == null) 0 else cell.toString.length)
val colSizes = for (col <- sizes.transpose) yield col.max
val rows = for (row <- table) yield formatRow(row, colSizes)
formatRows(rowSeparator(colSizes), rows, isHeaderNeeded)
}
def formatRes(table: Array[org.apache.spark.sql.Row]): String = {
val res: Seq[Seq[Any]] = (for { r <- table } yield r.toSeq).toSeq
format(res, false)
}
def formatDf(df: org.apache.spark.sql.DataFrame, n: Int = 20, isHeaderNeeded: Boolean = true): String = {
val res: Seq[Seq[Any]] = (for { r <- df.take(n) } yield r.toSeq).toSeq
format(List(df.schema.map(_.name).toSeq) ++ res, isHeaderNeeded)
}
def apply(table: Array[org.apache.spark.sql.Row]): Unit =
println(formatRes(table))
/**
* Print DataFrame in a formatted manner.
* @param df Data frame
* @param n How many row to take for tabular printing
*/
def apply(df: org.apache.spark.sql.DataFrame, n: Int = 20, isHeaderNeeded: Boolean = true): Unit =
println(formatDf(df, n, isHeaderNeeded))
def formatRows(rowSeparator: String, rows: Seq[String], isHeaderNeeded: Boolean): String = (
rowSeparator ::
(rows.head + { if (isHeaderNeeded) "\n" + rowSeparator else "" }) ::
rows.tail.toList :::
rowSeparator ::
List()).mkString("\n")
def formatRow(row: Seq[Any], colSizes: Seq[Int]) = {
val cells = (for ((item, size) <- row.zip(colSizes)) yield if (size == 0) "" else ("%" + size + "s").format(item))
cells.mkString("|", "|", "|")
}
def rowSeparator(colSizes: Seq[Int]) = colSizes map { "-" * _ } mkString("+", "+", "+")
}