C# Tips: Draw a data table in console
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace datatable
{
public class ConsoleTable
{
/// <summary>
/// This will hold the header of the table.
/// </summary>
private string[] header; /// <summary>
/// This will hold the rows (lines) in the table, not including the
/// header. I'm using a List of lists because it's easier to deal with...
/// </summary>
private List<List<string>> rows; /// <summary>
/// This is the default element (character/string) that will be put
/// in the table when user adds invalid data, example:
/// ConsoleTable ct = new ConsoleTable();
/// ct.AddRow(new List<string> { null, "bla", "bla" });
/// That null will be replaced with "DefaultElement", also, empty
/// strings will be replaced with this value.
/// </summary>
private const string DefaultElement = "X"; public enum AlignText
{
ALIGN_RIGHT,
ALIGN_LEFT,
} public ConsoleTable()
{
header = null;
rows = new List<List<string>>();
TextAlignment = AlignText.ALIGN_LEFT;
} /// <summary>
/// Set text alignment in table cells, either RIGHT or LEFT.
/// </summary>
public AlignText TextAlignment
{
get;
set;
} public void SetHeaders(string[] h)
{
header = h;
} public void AddRow(List<string> row)
{
rows.Add(row);
} private void AppendLine(StringBuilder hsb, int length)
{
// " " length is 1
// "\r\n" length is 2
// +1 length because I want the output to be prettier
// Hence the length - 4 ...
hsb.Append(" ");
hsb.Append(new string('-', length - ));
hsb.Append("\r\n");
} /// <summary>
/// This function returns the maximum possible length of an
/// individual row (line). Of course that if we use table header,
/// the maximum length of an individual row should equal the
/// length of the header.
/// </summary>
private int GetMaxRowLength()
{
if (header != null)
return header.Length;
else
{
int maxlen = rows[].Count;
for (int i = ; i < rows.Count; i++)
if (rows[i].Count > maxlen)
maxlen = rows[i].Count; return maxlen;
}
} private void PutDefaultElementAndRemoveExtra()
{
int maxlen = GetMaxRowLength(); for (int i = ; i < rows.Count; i++)
{
// If we find a line that is smaller than the biggest line,
// we'll add DefaultElement at the end of that line. In the end
// the line will be as big as the biggest line.
if (rows[i].Count < maxlen)
{
int loops = maxlen - rows[i].Count;
for (int k = ; k < loops; k++)
rows[i].Add(DefaultElement);
}
else if (rows[i].Count > maxlen)
{
// This will apply only when header != null, and we try to
// add a line bigger than the header line. Remove the elements
// of the line, from right to left, until the line is equal
// with the header line.
rows[i].RemoveRange(maxlen, rows[i].Count - maxlen);
} // Find bad data, loop through all table elements.
for (int j = ; j < rows[i].Count; j++)
{
if (rows[i][j] == null)
rows[i][j] = DefaultElement;
else if (rows[i][j] == "")
rows[i][j] = DefaultElement;
}
}
} /// <summary>
/// This function will return an array of integers, an element at
/// position 'i' will return the maximum length from column 'i'
/// of the table (if we look at the table as a matrix).
/// </summary>
private int[] GetWidths()
{
int[] widths = null;
if (header != null)
{
// Initially we assume that the maximum length from column 'i'
// is exactly the length of the header from column 'i'.
widths = new int[header.Length];
for (int i = ; i < header.Length; i++)
widths[i] = header[i].ToString().Length;
}
else
{
int count = GetMaxRowLength();
widths = new int[count];
for (int i = ; i < count; i++)
widths[i] = -;
} foreach (List<string> s in rows)
{
for (int i = ; i < s.Count; i++)
{
s[i] = s[i].Trim();
if (s[i].Length > widths[i])
widths[i] = s[i].Length;
}
} return widths;
} /// <summary>
/// Returns a valid format that is to be passed to AppendFormat
/// member function of StringBuilder.
/// General form: "|{i, +/-widths[i]}|", where 0 <= i <= widths.Length - 1
/// and widths[i] represents the maximum width from column 'i'.
/// </summary>
/// <param name="widths">The array of widths presented above.</param>
private string BuildRowFormat(int[] widths)
{
string rowFormat = String.Empty;
for (int i = ; i < widths.Length; i++)
{
if (TextAlignment == AlignText.ALIGN_LEFT)
rowFormat += "| {" + i.ToString() + ",-" + (widths[i]) + "} ";
else
rowFormat += "| {" + i.ToString() + "," + (widths[i]) + "} ";
} rowFormat = rowFormat.Insert(rowFormat.Length, "|\r\n");
return rowFormat;
} /// <summary>
/// Prints the table, main function.
/// </summary>
public void PrintTable()
{
if (rows.Count == )
{
Console.WriteLine("Can't create a table without any rows.");
return;
}
PutDefaultElementAndRemoveExtra(); int[] widths = GetWidths();
string rowFormat = BuildRowFormat(widths); // I'm using a temporary string builder to find the total width
// of the table, and increase BufferWidth of Console if necessary.
StringBuilder toFindLen = new StringBuilder();
toFindLen.AppendFormat(rowFormat, (header == null ? rows[].ToArray() : header));
int length = toFindLen.Length;
if (Console.BufferWidth < length)
Console.BufferWidth = length; // Print the first row, or header (if it exist), you can see that AppendLine
// is called before/after every AppendFormat.
StringBuilder hsb = new StringBuilder();
AppendLine(hsb, length);
hsb.AppendFormat(rowFormat, (header == null ? rows[].ToArray() : header));
AppendLine(hsb, length); // If header does't exist, we start from 1 because the first row
// was already printed above.
int idx = ;
if (header == null)
idx = ;
for (int i = idx; i < rows.Count; i++)
{
hsb.AppendFormat(rowFormat, rows[i].ToArray());
AppendLine(hsb, length);
} Console.WriteLine(hsb.ToString());
} static void Main(string[] args)
{
// Some test table, with header, and 3 lines by 3 columns.
ConsoleTable ct = new ConsoleTable();
ct.TextAlignment = ConsoleTable.AlignText.ALIGN_RIGHT;
ct.SetHeaders(new string[] { "ID", "Name", "City" });
ct.AddRow(new List<string> { "", "John", "New York" });
ct.AddRow(new List<string> { "", "Mark", "Washington" });
ct.AddRow(new List<string> { "", "Alice", "Chicago" });
ct.PrintTable();
}
}
}
C# Tips: Draw a data table in console的更多相关文章
- [Javascript] Logging Pretty-Printing Tabular Data to the Console
Learn how to use console.table to render arrays and objects in a tabular format for easy scanning ov ...
- data.table包
data.table 1.生成一个data.table对象 生成一个data.table对象,记为DT. library(data.table) :],V3=round(rnorm(),),V4=:) ...
- R之data.table -melt/dcast(数据合并和拆分)
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 30.0px "Helvetica Neue"; color: #323333 } p. ...
- R之data.table速查手册
R语言data.table速查手册 介绍 R中的data.table包提供了一个data.frame的高级版本,让你的程序做数据整型的运算速度大大的增加.data.table已经在金融,基因工程学等领 ...
- 两种Data Table参数化设置的区别
首先介绍Data Table的语法: 1.DataTable.value(ParameterID, SheetID) 2.DataTable(ParameterID, SheetID) 以上2种方法的 ...
- R语言数据分析利器data.table包 —— 数据框结构处理精讲
R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代码简洁,只要一行命令就可以完成诸多任务,另一方面是处理 ...
- R语言基因组数据分析可能会用到的data.table函数整理
R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代码简洁,只要一行命令就可以完成诸多任务,另一方面是处理快,内部 ...
- 将基因组数据分类并写出文件,python,awk,R data.table速度PK
由于基因组数据过大,想进一步用R语言处理担心系统内存不够,因此想着将文件按染色体拆分,发现python,awk,R 语言都能够非常简单快捷的实现,那么速度是否有差距呢,因此在跑几个50G的大文件之前, ...
- data.table包简介
data.table包主要特色是:设置keys.快速分组和滚得时序的快速合并.data.table主要通过二元检索法大大提高数据操作的效率,同时它也兼容适用于data.frame的向量检索法. req ...
随机推荐
- c# implicit explicit关键字(隐式和显式数据类型转换)
implicit关键字用于声明隐式的用户定义类型转换运算符.(explicit反之)explicit则用于显示转换用户自定义类型.static implicit operator target_typ ...
- CUDA Memories--CUDA记忆体(翻译+整理+测试)
一边学习一边记录(本文中英结合,专业名词统统不翻译) 在CUDA里,host和devices有不同的记忆体空间. 首先呢,CUDA的memory有很多种类啦 1. Global memory 2. C ...
- jQuery循环滚动新闻列表
最近由于项目原因,学习了下jquery,实现了一个小小的功能,就是点击公告的上一条下一条来查看滚动条.具体代码如下: <!DOCTYPE html PUBLIC "-//W3C//DT ...
- 标准SAP中的物料类型
DIEN -服务 ERSA -备件 FERT -成品 HALB -半成品 HAWA -贸易商品 HIBE -经营供应 LEER -虚拟件 NLAG -费存储物料 ROH -原材料 VERP -包装 W ...
- Qt学习之自定义窗口部件
自定义Qt窗口部件 实现一个十六进制的SpinBox,一般SpinBox只支持十进制整数,但是可以子类化方法实现该功能 需重新实现以下虚函数 virtual QString textFromValue ...
- linux C 执行多个文件
- javascript------>delete
delete只能删除属性,不能删除变量 var a = "roboce"; delete a; // false a; b = "haha"; delete b ...
- [MySQL登录错误] ERROR1045 (28000): Access denied for user 'omonroy'@'20.112.251.19' (using password:YES)
收到美国那边同事carl的call说用户登录不上去了,不过2个礼拜前他还用的好好的,他给我发email了,他有急事需要处理麻烦我记尽快协助,他在email有截取错误信息: root@xxxxx:/ho ...
- Using UTL_DBWS to Make a Database 11g Callout to a Document Style Web Service
In this Document _afrLoop=100180147230187&id=841183.1&displayIndex=2&_afrWindowMode=0& ...
- h5-3
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...