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.

Revisions

  1. uzluisf created this gist Jun 14, 2023.
    136 changes: 136 additions & 0 deletions create-table-raku.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,136 @@
    <details open>
    <summary><h3>Raku code</h3></summary>

    ```raku
    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;
    }
    ```
    </details>

    ### Usage

    ```raku
    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 |
    ```