I have an interesting question. Imagine I have a lot of data changing in very fast intervals. I want to display that data as a table in console app. f.ex:
-------------------------------------------------------------------------
| Column 1 | Column 2 | Column 3 | Column 4 |
-------------------------------------------------------------------------
| | | | |
| | | | |
| | | | |
-------------------------------------------------------------------------
How to keep things fast and how to fix column widths ? I know how to do that in java, but I don't how it's done in C#.
Edit: thanks to @superlogical, you can now find and improve the following code in github!
I wrote this class based on some ideas here. The columns width is optimal, an it can handle object arrays with this simple API:
static void Main(string[] args)
{
IEnumerable<Tuple<int, string, string>> authors =
new[]
{
Tuple.Create(1, "Isaac", "Asimov"),
Tuple.Create(2, "Robert", "Heinlein"),
Tuple.Create(3, "Frank", "Herbert"),
Tuple.Create(4, "Aldous", "Huxley"),
};
Console.WriteLine(authors.ToStringTable(
new[] {"Id", "First Name", "Surname"},
a => a.Item1, a => a.Item2, a => a.Item3));
/* Result:
| Id | First Name | Surname |
|----------------------------|
| 1 | Isaac | Asimov |
| 2 | Robert | Heinlein |
| 3 | Frank | Herbert |
| 4 | Aldous | Huxley |
*/
}
Here is the class:
public static class TableParser
{
public static string ToStringTable<T>(
this IEnumerable<T> values,
string[] columnHeaders,
params Func<T, object>[] valueSelectors)
{
return ToStringTable(values.ToArray(), columnHeaders, valueSelectors);
}
public static string ToStringTable<T>(
this T[] values,
string[] columnHeaders,
params Func<T, object>[] valueSelectors)
{
Debug.Assert(columnHeaders.Length == valueSelectors.Length);
var arrValues = new string[values.Length + 1, valueSelectors.Length];
// Fill headers
for (int colIndex = 0; colIndex < arrValues.GetLength(1); colIndex++)
{
arrValues[0, colIndex] = columnHeaders[colIndex];
}
// Fill table rows
for (int rowIndex = 1; rowIndex < arrValues.GetLength(0); rowIndex++)
{
for (int colIndex = 0; colIndex < arrValues.GetLength(1); colIndex++)
{
arrValues[rowIndex, colIndex] = valueSelectors[colIndex]
.Invoke(values[rowIndex - 1]).ToString();
}
}
return ToStringTable(arrValues);
}
public static string ToStringTable(this string[,] arrValues)
{
int[] maxColumnsWidth = GetMaxColumnsWidth(arrValues);
var headerSpliter = new string('-', maxColumnsWidth.Sum(i => i + 3) - 1);
var sb = new StringBuilder();
for (int rowIndex = 0; rowIndex < arrValues.GetLength(0); rowIndex++)
{
for (int colIndex = 0; colIndex < arrValues.GetLength(1); colIndex++)
{
// Print cell
string cell = arrValues[rowIndex, colIndex];
cell = cell.PadRight(maxColumnsWidth[colIndex]);
sb.Append(" | ");
sb.Append(cell);
}
// Print end of line
sb.Append(" | ");
sb.AppendLine();
// Print splitter
if (rowIndex == 0)
{
sb.AppendFormat(" |{0}| ", headerSpliter);
sb.AppendLine();
}
}
return sb.ToString();
}
private static int[] GetMaxColumnsWidth(string[,] arrValues)
{
var maxColumnsWidth = new int[arrValues.GetLength(1)];
for (int colIndex = 0; colIndex < arrValues.GetLength(1); colIndex++)
{
for (int rowIndex = 0; rowIndex < arrValues.GetLength(0); rowIndex++)
{
int newLength = arrValues[rowIndex, colIndex].Length;
int oldLength = maxColumnsWidth[colIndex];
if (newLength > oldLength)
{
maxColumnsWidth[colIndex] = newLength;
}
}
}
return maxColumnsWidth;
}
}
Edit: I added a minor improvement - if you want the column headers to be the property name, add the following method to TableParser
(note that it will be a bit slower due to reflection):
public static string ToStringTable<T>(
this IEnumerable<T> values,
params Expression<Func<T, object>>[] valueSelectors)
{
var headers = valueSelectors.Select(func => GetProperty(func).Name).ToArray();
var selectors = valueSelectors.Select(exp => exp.Compile()).ToArray();
return ToStringTable(values, headers, selectors);
}
private static PropertyInfo GetProperty<T>(Expression<Func<T, object>> expresstion)
{
if (expresstion.Body is UnaryExpression)
{
if ((expresstion.Body as UnaryExpression).Operand is MemberExpression)
{
return ((expresstion.Body as UnaryExpression).Operand as MemberExpression).Member as PropertyInfo;
}
}
if ((expresstion.Body is MemberExpression))
{
return (expresstion.Body as MemberExpression).Member as PropertyInfo;
}
return null;
}
It's easier in VisualBasic.net!
If you want the user to be able to manually enter data into a table:
Console.Write("Enter Data For Column 1: ")
Dim Data1 As String = Console.ReadLine
Console.Write("Enter Data For Column 2: ")
Dim Data2 As String = Console.ReadLine
Console.WriteLine("{0,-20} {1,-10} {2,-10}", "{Data Type}", "{Column 1}", "{Column 2}")
Console.WriteLine("{0,-20} {1,-10} {2,-10}", "Data Entered:", Data1, Data2)
Console.WriteLine("ENTER To Exit: ")
Console.ReadLine()
It should look like this:
Use MarkDownLog library (you can find it on NuGet)
you can simply use the extension ToMarkdownTable() to any collection, it does all the formatting for you.
Console.WriteLine(
yourCollection.Select(s => new
{
column1 = s.col1,
column2 = s.col2,
column3 = s.col3,
StaticColumn = "X"
})
.ToMarkdownTable());
Output looks something like this:
Column1 | Column2 | Column3 | StaticColumn
--------:| ---------:| ---------:| --------------
| | | X
I wanted variable-width columns, and I didn't particularly care about the box characters. Also, I needed to print some extra information for each row.
So in case anyone else needs that, I'll save you few minutes:
public class TestTableBuilder
{
public interface ITextRow
{
String Output();
void Output(StringBuilder sb);
Object Tag { get; set; }
}
public class TableBuilder : IEnumerable<ITextRow>
{
protected class TextRow : List<String>, ITextRow
{
protected TableBuilder owner = null;
public TextRow(TableBuilder Owner)
{
owner = Owner;
if (owner == null) throw new ArgumentException("Owner");
}
public String Output()
{
StringBuilder sb = new StringBuilder();
Output(sb);
return sb.ToString();
}
public void Output(StringBuilder sb)
{
sb.AppendFormat(owner.FormatString, this.ToArray());
}
public Object Tag { get; set; }
}
public String Separator { get; set; }
protected List<ITextRow> rows = new List<ITextRow>();
protected List<int> colLength = new List<int>();
public TableBuilder()
{
Separator = " ";
}
public TableBuilder(String separator)
: this()
{
Separator = separator;
}
public ITextRow AddRow(params object[] cols)
{
TextRow row = new TextRow(this);
foreach (object o in cols)
{
String str = o.ToString().Trim();
row.Add(str);
if (colLength.Count >= row.Count)
{
int curLength = colLength[row.Count - 1];
if (str.Length > curLength) colLength[row.Count - 1] = str.Length;
}
else
{
colLength.Add(str.Length);
}
}
rows.Add(row);
return row;
}
protected String _fmtString = null;
public String FormatString
{
get
{
if (_fmtString == null)
{
String format = "";
int i = 0;
foreach (int len in colLength)
{
format += String.Format("{{{0},-{1}}}{2}", i++, len, Separator);
}
format += "\r\n";
_fmtString = format;
}
return _fmtString;
}
}
public String Output()
{
StringBuilder sb = new StringBuilder();
foreach (TextRow row in rows)
{
row.Output(sb);
}
return sb.ToString();
}
#region IEnumerable Members
public IEnumerator<ITextRow> GetEnumerator()
{
return rows.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return rows.GetEnumerator();
}
#endregion
}
static void Main(String[] args)
{
TableBuilder tb = new TableBuilder();
tb.AddRow("When", "ID", "Name");
tb.AddRow("----", "--", "----");
tb.AddRow(DateTime.Now, "1", "Name1");
tb.AddRow(DateTime.Now, "1", "Name2");
Console.Write(tb.Output());
Console.WriteLine();
// or
StringBuilder sb = new StringBuilder();
int i = 0;
foreach (ITextRow tr in tb)
{
tr.Output(sb);
if (i++ > 1) sb.AppendLine("more stuff per line");
}
Console.Write(sb.ToString());
}
}
Output:
When ID Name ---- -- ---- 2/4/2013 8:37:44 PM 1 Name1 2/4/2013 8:37:44 PM 1 Name2 When ID Name ---- -- ---- 2/4/2013 8:37:44 PM 1 Name1 more stuff per line 2/4/2013 8:37:44 PM 1 Name2 more stuff per line
In case if this helps someone, this is a simple class I wrote for my need. You can change it easily to fit your needs.
using System.Collections.Generic;
using System.Linq;
namespace Utilities
{
public class TablePrinter
{
private readonly string[] titles;
private readonly List<int> lengths;
private readonly List<string[]> rows = new List<string[]>();
public TablePrinter(params string[] titles)
{
this.titles = titles;
lengths = titles.Select(t => t.Length).ToList();
}
public void AddRow(params object[] row)
{
if (row.Length != titles.Length)
{
throw new System.Exception($"Added row length [{row.Length}] is not equal to title row length [{titles.Length}]");
}
rows.Add(row.Select(o => o.ToString()).ToArray());
for (int i = 0; i < titles.Length; i++)
{
if (rows.Last()[i].Length > lengths[i])
{
lengths[i] = rows.Last()[i].Length;
}
}
}
public void Print()
{
lengths.ForEach(l => System.Console.Write("+-" + new string('-', l) + '-'));
System.Console.WriteLine("+");
string line = "";
for (int i = 0; i < titles.Length; i++)
{
line += "| " + titles[i].PadRight(lengths[i]) + ' ';
}
System.Console.WriteLine(line + "|");
lengths.ForEach(l => System.Console.Write("+-" + new string('-', l) + '-'));
System.Console.WriteLine("+");
foreach (var row in rows)
{
line = "";
for (int i = 0; i < row.Length; i++)
{
if (int.TryParse(row[i], out int n))
{
line += "| " + row[i].PadLeft(lengths[i]) + ' '; // numbers are padded to the left
}
else
{
line += "| " + row[i].PadRight(lengths[i]) + ' ';
}
}
System.Console.WriteLine(line + "|");
}
lengths.ForEach(l => System.Console.Write("+-" + new string('-', l) + '-'));
System.Console.WriteLine("+");
}
}
}
Sample usage:
var t = new TablePrinter("id", "Column A", "Column B");
t.AddRow(1, "Val A1", "Val B1");
t.AddRow(2, "Val A2", "Val B2");
t.AddRow(100, "Val A100", "Val B100");
t.Print();
Output:
+-----+----------+----------+
| id | Column A | Column B |
+-----+----------+----------+
| 1 | Val A1 | Val B1 |
| 2 | Val A2 | Val B2 |
| 100 | Val A100 | Val B100 |
+-----+----------+----------+
This is an improvement to a previous answer. It adds support for values with varying lengths and rows with a varying number of cells. For example:
+------------------------------------------------------------------------------+
¦Identifier¦ Type¦ Description¦ CPU Credit Use¦Hours¦Balance¦
+----------+---------+--------------------------+----------------+-----+-------+
¦ i-1234154¦ t2.small¦ This is an example.¦ 3263.75¦ 360¦
+----------+---------+--------------------------+----------------+-----+
¦ i-1231412¦ t2.small¦ This is another example.¦ 3089.93¦
+----------------------------------------------------------------+
Here is the code:
public class ArrayPrinter
{
const string TOP_LEFT_JOINT = "+";
const string TOP_RIGHT_JOINT = "+";
const string BOTTOM_LEFT_JOINT = "+";
const string BOTTOM_RIGHT_JOINT = "+";
const string TOP_JOINT = "-";
const string BOTTOM_JOINT = "-";
const string LEFT_JOINT = "+";
const string JOINT = "+";
const string RIGHT_JOINT = "¦";
const char HORIZONTAL_LINE = '-';
const char PADDING = ' ';
const string VERTICAL_LINE = "¦";
private static int[] GetMaxCellWidths(List<string[]> table)
{
int maximumCells = 0;
foreach (Array row in table)
{
if (row.Length > maximumCells)
maximumCells = row.Length;
}
int[] maximumCellWidths = new int[maximumCells];
for (int i = 0; i < maximumCellWidths.Length; i++)
maximumCellWidths[i] = 0;
foreach (Array row in table)
{
for (int i = 0; i < row.Length; i++)
{
if (row.GetValue(i).ToString().Length > maximumCellWidths[i])
maximumCellWidths[i] = row.GetValue(i).ToString().Length;
}
}
return maximumCellWidths;
}
public static string GetDataInTableFormat(List<string[]> table)
{
StringBuilder formattedTable = new StringBuilder();
Array nextRow = table.FirstOrDefault();
Array previousRow = table.FirstOrDefault();
if (table == null || nextRow == null)
return String.Empty;
// FIRST LINE:
int[] maximumCellWidths = GetMaxCellWidths(table);
for (int i = 0; i < nextRow.Length; i++)
{
if (i == 0 && i == nextRow.Length - 1)
formattedTable.Append(String.Format("{0}{1}{2}", TOP_LEFT_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), TOP_RIGHT_JOINT));
else if (i == 0)
formattedTable.Append(String.Format("{0}{1}", TOP_LEFT_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE)));
else if (i == nextRow.Length - 1)
formattedTable.AppendLine(String.Format("{0}{1}{2}", TOP_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), TOP_RIGHT_JOINT));
else
formattedTable.Append(String.Format("{0}{1}", TOP_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE)));
}
int rowIndex = 0;
int lastRowIndex = table.Count - 1;
foreach (Array thisRow in table)
{
// LINE WITH VALUES:
int cellIndex = 0;
int lastCellIndex = thisRow.Length - 1;
foreach (object thisCell in thisRow)
{
string thisValue = thisCell.ToString().PadLeft(maximumCellWidths[cellIndex], PADDING);
if (cellIndex == 0 && cellIndex == lastCellIndex)
formattedTable.AppendLine(String.Format("{0}{1}{2}", VERTICAL_LINE, thisValue, VERTICAL_LINE));
else if (cellIndex == 0)
formattedTable.Append(String.Format("{0}{1}", VERTICAL_LINE, thisValue));
else if (cellIndex == lastCellIndex)
formattedTable.AppendLine(String.Format("{0}{1}{2}", VERTICAL_LINE, thisValue, VERTICAL_LINE));
else
formattedTable.Append(String.Format("{0}{1}", VERTICAL_LINE, thisValue));
cellIndex++;
}
previousRow = thisRow;
// SEPARATING LINE:
if (rowIndex != lastRowIndex)
{
nextRow = table[rowIndex + 1];
int maximumCells = Math.Max(previousRow.Length, nextRow.Length);
for (int i = 0; i < maximumCells; i++)
{
if (i == 0 && i == maximumCells - 1)
{
formattedTable.Append(String.Format("{0}{1}{2}", LEFT_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), RIGHT_JOINT));
}
else if (i == 0)
{
formattedTable.Append(String.Format("{0}{1}", LEFT_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE)));
}
else if (i == maximumCells - 1)
{
if (i > previousRow.Length)
formattedTable.AppendLine(String.Format("{0}{1}{2}", TOP_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), TOP_RIGHT_JOINT));
else if (i > nextRow.Length)
formattedTable.AppendLine(String.Format("{0}{1}{2}", BOTTOM_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), BOTTOM_RIGHT_JOINT));
else if (i > previousRow.Length - 1)
formattedTable.AppendLine(String.Format("{0}{1}{2}", JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), TOP_RIGHT_JOINT));
else if (i > nextRow.Length - 1)
formattedTable.AppendLine(String.Format("{0}{1}{2}", JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), BOTTOM_RIGHT_JOINT));
else
formattedTable.AppendLine(String.Format("{0}{1}{2}", JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), RIGHT_JOINT));
}
else
{
if (i > previousRow.Length)
formattedTable.Append(String.Format("{0}{1}", TOP_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE)));
else if (i > nextRow.Length)
formattedTable.Append(String.Format("{0}{1}", BOTTOM_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE)));
else
formattedTable.Append(String.Format("{0}{1}", JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE)));
}
}
}
rowIndex++;
}
// LAST LINE:
for (int i = 0; i < previousRow.Length; i++)
{
if (i == 0)
formattedTable.Append(String.Format("{0}{1}", BOTTOM_LEFT_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE)));
else if (i == previousRow.Length - 1)
formattedTable.AppendLine(String.Format("{0}{1}{2}", BOTTOM_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE), BOTTOM_RIGHT_JOINT));
else
formattedTable.Append(String.Format("{0}{1}", BOTTOM_JOINT, String.Empty.PadLeft(maximumCellWidths[i], HORIZONTAL_LINE)));
}
return formattedTable.ToString();
}
}
I have a project on GitHub that you can use
https://github.com/BrunoVT1992/ConsoleTable
You can use it like this:
var table = new Table();
table.SetHeaders("Name", "Date", "Number");
for (int i = 0; i <= 10; i++)
{
if (i % 2 == 0)
table.AddRow($"name {i}", DateTime.Now.AddDays(-i).ToLongDateString(), i.ToString());
else
table.AddRow($"long name {i}", DateTime.Now.AddDays(-i).ToLongDateString(), (i * 5000).ToString());
}
Console.WriteLine(table.ToString());
It will give this result:
public static void ToPrintConsole(this DataTable dataTable)
{
// Print top line
Console.WriteLine(new string('-', 75));
// Print col headers
var colHeaders = dataTable.Columns.Cast<DataColumn>().Select(arg => arg.ColumnName);
foreach (String s in colHeaders)
{
Console.Write("| {0,-20}", s);
}
Console.WriteLine();
// Print line below col headers
Console.WriteLine(new string('-', 75));
// Print rows
foreach (DataRow row in dataTable.Rows)
{
foreach (Object o in row.ItemArray)
{
Console.Write("| {0,-20}", o.ToString());
}
Console.WriteLine();
}
// Print bottom line
Console.WriteLine(new string('-', 75));
}
There're several open-source libraries which allow console table formatting, ranging from simple (like the code samples in the answers here) to more advanced.
Judging by NuGet stats, the most popular library for formatting tables is ConsoleTable. Tables are constructed like this (from the readme file):
var table = new ConsoleTable("one", "two", "three");
table.AddRow(1, 2, 3)
.AddRow("this line should be longer", "yes it is", "oh");
Tables can be formatted using one of the predefined styles. It'll look like this:
--------------------------------------------------
| one | two | three |
--------------------------------------------------
| 1 | 2 | 3 |
--------------------------------------------------
| this line should be longer | yes it is | oh |
--------------------------------------------------
This library expects single-line cells with no formatting.
There're a couple of libraries based on ConsoleTable with slightly extended feature sets, like more line styles.
If you need more complex formatting, you can use CsConsoleFormat.† Here's a table generated from a process list (from a sample project):
new Grid { Stroke = StrokeHeader, StrokeColor = DarkGray }
.AddColumns(
new Column { Width = GridLength.Auto },
new Column { Width = GridLength.Auto, MaxWidth = 20 },
new Column { Width = GridLength.Star(1) },
new Column { Width = GridLength.Auto }
)
.AddChildren(
new Cell { Stroke = StrokeHeader, Color = White }
.AddChildren("Id"),
new Cell { Stroke = StrokeHeader, Color = White }
.AddChildren("Name"),
new Cell { Stroke = StrokeHeader, Color = White }
.AddChildren("Main Window Title"),
new Cell { Stroke = StrokeHeader, Color = White }
.AddChildren("Private Memory"),
processes.Select(process => new[] {
new Cell { Stroke = StrokeRight }
.AddChildren(process.Id),
new Cell { Stroke = StrokeRight, Color = Yellow, TextWrap = TextWrapping.NoWrap }
.AddChildren(process.ProcessName),
new Cell { Stroke = StrokeRight, Color = White, TextWrap = TextWrapping.NoWrap }
.AddChildren(process.MainWindowTitle),
new Cell { Stroke = LineThickness.None, Align = HorizontalAlignment.Right }
.AddChildren(process.PrivateMemorySize64.ToString("n0")),
})
)
The end result will look like this:
It supports any kind of table lines (several included and customizable), multi-line cells with word wrap, colors, columns growing based on content or percentage, text alignment etc.
† CsConsoleFormat was developed by me.
Use String.Format with alignment values.
For example:
String.Format("|{0,5}|{1,5}|{2,5}|{3,5}|", arg0, arg1, arg2, arg3);
To create one formatted row.
class ArrayPrinter
{
#region Declarations
static bool isLeftAligned = false;
const string cellLeftTop = "+";
const string cellRightTop = "+";
const string cellLeftBottom = "+";
const string cellRightBottom = "+";
const string cellHorizontalJointTop = "-";
const string cellHorizontalJointbottom = "-";
const string cellVerticalJointLeft = "+";
const string cellTJoint = "+";
const string cellVerticalJointRight = "¦";
const string cellHorizontalLine = "-";
const string cellVerticalLine = "¦";
#endregion
#region Private Methods
private static int GetMaxCellWidth(string[,] arrValues)
{
int maxWidth = 1;
for (int i = 0; i < arrValues.GetLength(0); i++)
{
for (int j = 0; j < arrValues.GetLength(1); j++)
{
int length = arrValues[i, j].Length;
if (length > maxWidth)
{
maxWidth = length;
}
}
}
return maxWidth;
}
private static string GetDataInTableFormat(string[,] arrValues)
{
string formattedString = string.Empty;
if (arrValues == null)
return formattedString;
int dimension1Length = arrValues.GetLength(0);
int dimension2Length = arrValues.GetLength(1);
int maxCellWidth = GetMaxCellWidth(arrValues);
int indentLength = (dimension2Length * maxCellWidth) + (dimension2Length - 1);
//printing top line;
formattedString = string.Format("{0}{1}{2}{3}", cellLeftTop, Indent(indentLength), cellRightTop, System.Environment.NewLine);
for (int i = 0; i < dimension1Length; i++)
{
string lineWithValues = cellVerticalLine;
string line = cellVerticalJointLeft;
for (int j = 0; j < dimension2Length; j++)
{
string value = (isLeftAligned) ? arrValues[i, j].PadRight(maxCellWidth, ' ') : arrValues[i, j].PadLeft(maxCellWidth, ' ');
lineWithValues += string.Format("{0}{1}", value, cellVerticalLine);
line += Indent(maxCellWidth);
if (j < (dimension2Length - 1))
{
line += cellTJoint;
}
}
line += cellVerticalJointRight;
formattedString += string.Format("{0}{1}", lineWithValues, System.Environment.NewLine);
if (i < (dimension1Length - 1))
{
formattedString += string.Format("{0}{1}", line, System.Environment.NewLine);
}
}
//printing bottom line
formattedString += string.Format("{0}{1}{2}{3}", cellLeftBottom, Indent(indentLength), cellRightBottom, System.Environment.NewLine);
return formattedString;
}
private static string Indent(int count)
{
return string.Empty.PadLeft(count, '-');
}
#endregion
#region Public Methods
public static void PrintToStream(string[,] arrValues, StreamWriter writer)
{
if (arrValues == null)
return;
if (writer == null)
return;
writer.Write(GetDataInTableFormat(arrValues));
}
public static void PrintToConsole(string[,] arrValues)
{
if (arrValues == null)
return;
Console.WriteLine(GetDataInTableFormat(arrValues));
}
#endregion
static void Main(string[] args)
{
int value = 997;
string[,] arrValues = new string[5, 5];
for (int i = 0; i < arrValues.GetLength(0); i++)
{
for (int j = 0; j < arrValues.GetLength(1); j++)
{
value++;
arrValues[i, j] = value.ToString();
}
}
ArrayPrinter.PrintToConsole(arrValues);
Console.ReadLine();
}
}
Source: Stackoverflow.com