Skip to content

Instantly share code, notes, and snippets.

@uzluisf
Created June 14, 2023 23:56
Show Gist options
  • Save uzluisf/e71e4be9f0be1b09e152545c098b739e to your computer and use it in GitHub Desktop.
Save uzluisf/e71e4be9f0be1b09e152545c098b739e to your computer and use it in GitHub Desktop.
Small Raku subroutine to pretty print a table.

Raku code

sub create-table(:@headers, :@columns, Bool :$markdown = False --> Nil) {

    unless @headers.elems == @columns.elems {
        $*ERR.spurt: "Table is out of shape: Number of headers must be equal to number of columns.\n";
        $*ERR.flush;
        return;
    }
    
    unless [==] @columns».elems {
        $*ERR.spurt: "Table is out of shape: All columns must have the same length.\n";
        $*ERR.flush;
        return;
    }
 
    my constant $ADDITIONAL-SPACING = 2;
    my constant $COLUMN-SEPARATOR = '| ';
    my constant $LEFT-BOUNDARY = '| ';
    my constant $JOIN-SEPARATOR = '+';
    my constant $MARKDOWN-BOUNDARY = '|:';
   
    #
    # HEADING
    #

    my Str:D $row-separator = '';
    my @headers-to-max-col-values = [];
 
    for @headers.kv -> $idx, $header {
        my Int:D $max-col-value = @columns[$idx].max(:by(&chars)).chars;
        @headers-to-max-col-values.push($header => $max-col-value) for 0..^@columns[$idx].elems;

        my Str:D $heading-row = 
            ~ ($idx == 0 ?? $LEFT-BOUNDARY !! '')
            ~ $header
            ~ (' ' x ($max-col-value + $ADDITIONAL-SPACING + ($idx == 0 ?? 1 !! 0)))
            ~ $COLUMN-SEPARATOR
        ;

        $*OUT.spurt: $heading-row;

        if $markdown {
            $row-separator ~= 
                ~ ($idx == 0 ?? $MARKDOWN-BOUNDARY !! '')
                ~ '-' x ($header.chars + $max-col-value + $ADDITIONAL-SPACING + ($idx == 0 ?? $LEFT-BOUNDARY.chars !! 0) - 1)
                ~ $MARKDOWN-BOUNDARY
                ~ ($idx != @headers.end ?? '-' !! '');

            $row-separator .= chop(1) if $idx == @headers.end;
        }
        else {
            $row-separator ~= 
                ~ ($idx == 0 ?? $JOIN-SEPARATOR !! '')
                ~ '-' x ($header.chars + $max-col-value + $ADDITIONAL-SPACING + ($idx == 0 ?? $LEFT-BOUNDARY.chars !! 0))
                ~ $JOIN-SEPARATOR
                ~ ($idx != @headers.end ?? '-' !! '');
        }
        
        if $idx eq @headers.end {
            $*OUT.spurt: "\n$row-separator\n";
        }
    }

    #
    # ROWS
    #

    my Int:D $aligned-data-offset = @columns.min(:by(&elems)).elems;
    my Int:D $row-count = @headers.elems;
    my Int:D $next-idx = 0;
    my Int:D $newrow-indicator = 0;
    my Int:D $iterations = 0;
    my Str:D @values = @columns.map(*.Slip);
    my $m = @values.elems div @columns.head.elems;
    for 0 ..^ @values.elems -> $n {
        my $first-row = $n %% $m;
        my $pair = @headers-to-max-col-values[$next-idx];
        my Int:D $chars = $pair.value + $pair.key.chars + $ADDITIONAL-SPACING + ($first-row ?? 1 !! 0);
        my Str:D $row-part = sprintf("%-{$chars}s", @values[$next-idx]) ~ $COLUMN-SEPARATOR;

        if $next-idx >= @values.elems - $aligned-data-offset {
            $next-idx = $iterations + 1;
            $iterations += 1;
        }
        else {
            $next-idx += $aligned-data-offset
        }

        if $newrow-indicator >= $row-count {
            $*OUT.flush;
            $*OUT.spurt: "\n$LEFT-BOUNDARY";
            $newrow-indicator = 0;
        }
        else {
            $*OUT.spurt: $LEFT-BOUNDARY if $n == 0;
        }

        $*OUT.spurt: $row-part;
        $newrow-indicator += 1;
    }

    $*OUT.spurt: ("\n$row-separator" unless $markdown) ~ "\n";
    $*OUT.flush;
}

Usage

create-table
    headers => ["Process Name", "Arrival Time", "Service Time", "Turnaround Time"],
    columns => [
        ["P1", "P2", "P3", "P4", "P5"],
        ["1", "3", "6", "2", "3"],
        ["3", "1", "8", "1", "4"],
        ["3", "1", "8", "1", "4"],
    ],
    :markdown,
;

Output

| Process Name     | Arrival Time   | Service Time   | Turnaround Time   | 
|:-----------------|:---------------|:---------------|:------------------|
| P1               | 1              | 3              | 3                 | 
| P2               | 3              | 1              | 1                 | 
| P3               | 6              | 8              | 8                 | 
| P4               | 2              | 1              | 1                 | 
| P5               | 3              | 4              | 4                 |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment