In this tip, you will find a simple class for writing an array as a formatted, attractive table (title, row and column headers, data-aligned, etc.) to the console or other UI text display control.
Introduction
I program mostly in C# on an iMac with a Windows virtualbox
, doing a good bit of what might be called “one-off” scientific computing and typically using simple Winforms or the console as my UI (mostly console on the Mac side – Xamarin Mac apps are great but sometimes the UI programming overhead is more work than the program itself). During development, debugging, and experimenting, I typically need to view tables of data objects quickly and easily and so am constantly writing and rewriting custom Console.WriteLine
loops, etc. DataGridView
s and similar tools also are sometimes tedious to work with. Finally, I decided to write a custom “Table
” writer. Perhaps you have done that too.
I wanted a routine that I could just drop an array into and receive back a nice output string. A routine that worked with all sorts of arrays and collections, could be modified or expanded easily, offered nice row and column headers, maybe a title, and neatly aligned data elements. Originally, I was mostly concerned with numerical data tables, so the basic table element was a formatted double
. But since the output was to be a “stringbuilt” string
anyway, here I decided to use string
s as the basic element to begin with. And to tolerate three copies in memory (original array, string
array, and stringbuilt string
) for a moment or two. After all, the table
objects I want to print are seldom enormous; memory is seldom a problem; and the objects are disposed after one time use, etc.
Here is the code for my Table
object generator. Nothing special and surely improvable. This should be easy to modify for custom purposes. One note is that column widths are determined by the “widest” value in each column. String
values are then aligned Left
, Center
or Right
within those widths. The download provides examples of other type constructors and special writers (e.g., for CSV string
s). If you are using a ListView
control of some kind or, eventually, a text document, this table writer is designed for a monospaced font. I hope readers might find this a handy and useful addition to their personal code libraries.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
namespace TablePlay
{
public class Table
{
private string title;
private readonly int cols;
private readonly int rows;
private readonly int colSpace;
private string colSpaceStr;
private int[] maxColWidths;
private CultureInfo culture;
private string numFormat;
private string[] colHdrs;
private string[] rowHdrs;
private readonly string[,] array;
private readonly StringBuilder sb = new StringBuilder();
#region CONSTRUCTORS
public Table(int[] ar, int columnSpace = 1, bool prtincol = false)
{ .... }
public Table(int[,] ar, int columnSpace = 1)
{ .... }
public Table(double[,] ar, int dec = 3, int columnSpace = 1)
{
culture = CultureInfo.CreateSpecificCulture("en-US");
numFormat = "F" + dec.ToString();
colSpace = columnSpace;
rows = ar.GetLength(0);
cols = ar.GetLength(1);
array = new string[rows, cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
array[i, j] = ar[i, j].ToString(numFormat, culture);
Initialize();
}
public Table(String[,] ar, int columnSpace = 1)
{ .... }
private void Initialize()
{
title = "";
maxColWidths = new int[cols + 1];
colSpaceStr = new string(' ', colSpace);
colHdrs = new string[cols + 1];
rowHdrs = new string[rows];
Array.Fill(colHdrs, "");
Array.Fill(rowHdrs, "");
for (int j = 0; j < cols; j++)
for (int i = 0; i < rows; i++)
{
int len = array[i, j].Length;
if (maxColWidths[j + 1] < len) maxColWidths[j + 1] = len;
}
sb.Clear();
}
#endregion
#region METHODS
public string Title
{
get { return title; }
set { title = value; }
}
public string[] ColHdrs
{
get {return colHdrs;}
set
{
int n = value.Length > cols + 1 ? cols + 1 : value.Length;
for (int j = 0; j < n; j++) if (value[j] is not null) colHdrs[j] = value[j];
}
}
public string[] RowHdrs
{ .... }
public string GetTable()
{
string s = "";
maxColWidths[0] = colHdrs[0].Length;
for (int i = 0; i < rows; i++)
{
if (maxColWidths[0] < rowHdrs[i].Length) maxColWidths[0] = rowHdrs[i].Length;
}
s += StringUtils.Left(colHdrs[0], maxColWidths[0]);
for (int j = 1; j < cols + 1; j++)
{
if (maxColWidths[j] < colHdrs[j].Length) maxColWidths[j] = colHdrs[j].Length;
s += colSpaceStr + StringUtils.Center(colHdrs[j], maxColWidths[j]);
}
if (title is not "") sb.Append(StringUtils.Center(title, s.Length) + "\n");
bool colHdrFlag = false;
for (int j = 0; j < cols + 1; j++) if (colHdrs[j] != "") colHdrFlag = true;
if (colHdrFlag)
{
sb.Append(s + "\n");
sb.Append(new string
('\u2015', maxColWidths.Sum() + cols * colSpace) + "\n");
}
for (int i = 0; i < rows; i++)
{
s = $"{StringUtils.Left(rowHdrs[i], maxColWidths[0])}";
for (int j = 0; j < cols; j++)
s += colSpaceStr + StringUtils.Right(array[i, j], maxColWidths[j + 1]);
sb.Append(s + "\n");
}
return sb.ToString();
}
#endregion
public class StringUtils
{
public static string Left(string s, int size, char pad = ' ')
{
try { if (size <= s.Length) return s; }
catch { return s; }
StringBuilder sb = new StringBuilder(size);
sb.Append(s);
while (sb.Length < size) sb.Append(pad);
return sb.ToString();
}
public static string Right(string s, int size, char pad = ' ')
{ .... }
public static string Center(string s, int size, char pad = ' ')
{ .... }
public static string CSVWriter(List<string> csvstrings,
int columnSpace = 1, string title = "")
{ .... }
}
}
}
Using the Code
This table writer works well with Visual Studio for Windows and Visual Studio for Mac. Here is a sample of code to call the table writer and display output.
double[,] Rxy = new double[3, 3] {
{ 1.0, -.25, 0.123 },
{ -.25, 1.0, .300 },
{ 0.123, 0.300, 1.0 } };
Table myTable1 = new Table(Rxy) {
Title = "TABLE 1: Correlation Matrix",
ColHdrs = new[] { "Rxy", "C1", "C2", "C3" },
RowHdrs = new[] { "C1", "C2", "C3" } };
Console.WriteLine(myTable1.GetTable());
There are many interesting articles on formatting tables on CodeProject and other sources. For example, check out:
History
- 26th January, 2021: Initial version