C# helper method to show tabular data in the console.

using System;
using System.Collections.Generic;
using System.Linq;

namespace MsPressClr.Console
{
    /// <summary>
    /// Console table formatter.
    /// </summary>
    /// <remarks>
    /// https://github.com/dotnet/templating/blob/rel/vs2017/3-Preview3/src/Microsoft.TemplateEngine.Cli/TableFormatter.cs
    /// </remarks>
    public static class TableFormatter
    {
        public static void Print<T>(IEnumerable<T> items, string noItemsMessage,
                                    string columnPad, char header,
                                    Dictionary<string, Func<T, object>> dictionary)
        {
            var headers = new string[dictionary.Count];
            var columnWidths = new int[dictionary.Count];
            var columns = new List<string>[dictionary.Count];
            var valueCount = 0;

            for (var i = 0; i < dictionary.Count; ++i)
            {
                columns[i] = new List<string>();
            }

            foreach (T item in items)
            {
                var index = 0;
                foreach (var act in dictionary)
                {
                    headers[index] = act.Key;
                    columns[index++].Add(act.Value(item)?.ToString() ?? "(null)");
                }
                ++valueCount;
            }

            if (valueCount > 0)
            {
                for (var i = 0; i < columns.Length; ++i)
                {
                    columnWidths[i] = Math.Max(
                        columns[i].Max(x => x.Length), headers[i].Length);
                }
            }
            else
            {
                var index = 0;
                foreach (var act in dictionary)
                {
                    headers[index] = act.Key;
                    columnWidths[index++] = act.Key.Length;
                }
            }

            var headerWidth = columnWidths.Sum() + columnPad.Length * (dictionary.Count - 1);
            for (var i = 0; i < headers.Length - 1; ++i)
            {
                System.Console.Write(headers[i].PadRight(columnWidths[i]));
                System.Console.Write(columnPad);
            }
            System.Console.WriteLine(headers[headers.Length - 1]);
            System.Console.WriteLine("".PadRight(headerWidth, header));

            for (var i = 0; i < valueCount; ++i)
            {
                for (var j = 0; j < columns.Length - 1; ++j)
                {
                    System.Console.Write(columns[j][i].PadRight(columnWidths[j]));
                    System.Console.Write(columnPad);
                }
                System.Console.WriteLine(columns[headers.Length - 1][i]);
            }

            if (valueCount == 0)
            {
                System.Console.WriteLine(noItemsMessage);
            }

            //System.Console.WriteLine(" ");
        }
    }
}



//
// Usage

var kvps = new List<KeyValuePair<string, string>>
{
    new KeyValuePair<string, string>("name", "Awesome App Title"),
    new KeyValuePair<string, string>("environment", "dev"),
    new KeyValuePair<string, string>("iWillBe", "deleted")
};

TableFormatter.Print(kvps, "N/A", " | ", '-',
    new Dictionary<string, System.Func<KeyValuePair<string, string>, object>>
{
    { "key", x => x.Key },
    { "value", x => x.Value }
});

// key         | value
// -------------------------------
// name        | Awesome App Title
// environment | dev
// iWillBe     | deleted