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 ...
随机推荐
- 不用FTP使用SecureCRT上传下载文件,并解决rz、sz command not found异常
使用SSH终端操作Linux/UNIX时,很多时候需要传一些文件到服务器上,或说从服务器上下载一些文件,这类文件传输动作一般使用FTP即可,但是需要架设FTP Server,每次传输不太方便,还要另外 ...
- Codeforces Round #337 (Div. 2) A. Pasha and Stick 数学
A. Pasha and Stick 题目连接: http://www.codeforces.com/contest/610/problem/A Description Pasha has a woo ...
- poj - 2774 - Long Long Message
题意:输入2个长度不超过100000的字符串,问它们最长公共子串的长度. 题目链接:http://poj.org/problem?id=2774 ——>>后缀数组!后缀数组!-从LJ的&l ...
- 大一C语言结课设计之《学生信息管理系统》
第一次写这么长的程序,代码仅供參考,有问题请留言. /* ** 学生信息管理系统 ** IDE:Dev-Cpp 4.9.9.2 ** 2014-6-15 */ #include <stdio.h ...
- 下一个系列学习列表Spring.net+NHibernate+MVC
开源框架完美组合之Spring.NET + NHibernate + ASP.NET MVC + jQuery + easyUI 中英文双语言小型企业网站Demo 刘冬.NET 2011-08-19 ...
- springMVC与struts2的区别
1. 机制:spring mvc的入口是servlet,而struts2是filter,这样就导致了二者的机制不同. 2. 性能:spring会稍微比struts快.spring mvc是基于方法的设 ...
- android中broadcastreceiver的用法-代码中注册
界面如下: 问题1:点击“解绑广播接收器“后再次点击”解绑广播接收器“后,程序崩溃,log信息如下: 08-04 05:04:35.420: E/AndroidRuntime(5521): F ...
- 《嵌入式Linux基础教程学习笔记一》
常用书目下载地址:http://www.cnblogs.com/pengdonglin137/p/3688029.html 第二章 1.进程上下文和中断上下文(Page20) 当应用程序执行系统调用, ...
- CentOS6.3配置yum源
转载:http://www.linuxidc.com/Linux/2012-10/72750.htm 全新以最小化包安装了64位的CentOS6.3系统,作为本地的Web服务器使用,现记录全过程第二步 ...
- LeetCode13 Roman to Integer
题意: Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from ...