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 ...
随机推荐
- Android - Facebook KeyHash 設定
转自:http://www.dotblogs.com.tw/newmonkey48/archive/2014/04/17/144779.aspx App要使用Facebook 分享時,設要在Faceb ...
- Uva110 Meta-Loopless Sorts
Meta-Loopless Sorts Background Sorting holds an important place in computer science. Analyzing and i ...
- 书写CSS需要注意的地方
1.注意对图片设置宽高和转化为块2.文字超出的设置3.空白部分用空div来设置4.做之前考虑重用,重用部分命名不要和内容相关 尽量公共(comWidth area small big img list ...
- JDBC-ODBC桥接方法连接Excel数据库的方法
通过JDBC-ODBC桥接器访问Excel电子表格 1.设置数据源 Excel数据源选择的驱动程序是Microsoft Excel Driver 2.选择表 与访问其他数据库不同的是,我们必须在电子表 ...
- Javascript 异步加载详解
Javascript 异步加载详解 本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy ...
- [MFC]MFC中OnDraw与OnPaint的区别
问题 问题:我在视图画的图象或者文字,当窗口改变后为什么不见了?OnDraw()和OnPaint()两个都是解决上面的问题,有什么不同? OnDraw()和OnPaint()好象兄弟俩,因为它们的工作 ...
- Android Studio中导入第三方库
之前开发Android都是使用的eclipse,近期因为和外国朋友Timothy一起开发一款应用,他是从WP平台刚切换使用Android的,使用的开发环境时Android Studio,为了便于项目的 ...
- sql server常用知识点
--删除表 use [20130823_Recource] go drop table my_table1,my_table2,My_table3 --创建表 use [20130823_Recour ...
- UIStoryboard
UIStoryboard 目录 概述 Storyboard的创建 Storyboard中的页面跳转 文件内跳转 文件外跳转 Segues 不同类型的视图控制器在UIStoryboard上的实现 概述 ...
- hung_task_timeout_secs 和 blocked for more than 120 seconds
https://help.aliyun.com/knowledge_detail/41544.html 问题现象 云服务器 ECS Linux 系统出现系统没有响应. 在/var/log/messag ...