Search code examples
arraysperlformatting

Multi-dimensional array formatted to console grid/columns


Using Text::Table or Text::ANSITable, or something similar...

If I have a two-dimensional array (which represents a grid of data), where the first row can be the column headers, how can I apply that data and format it into a command line grid with columns.

Something like this: PERL : How to create table from an array?

Except that the number of rows and columns is variable depending on the array setup and needs to automatically output as such.

Thanks


Solution

  • You can use Text::Table to accomplish this, as it handles variable numbers of rows and columns. Although the documentation leaves a lot to be desired, you can usually look to the test files or examples to show you how the library should actually get used. I've adapted example.pl to illustrate this:

    table.pl

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use utf8;
    
    use Text::Table;
    
    binmode STDOUT, ':utf8';
    
    my ($rows, $cols) = @ARGV;
    $rows ||= 5;
    $cols ||= 7;
    
    my @cols = map { "column " . $_} ( 1..$cols );
    my $sep = \'│';
    
    my $major_sep = \'║';
    my $tb = Text::Table->new($sep,  " Number ", $major_sep,
                              (map { +(" $_ ", $sep) } @cols)
        );
    
    my $num_cols = @cols;
    
    for my $row (1..$rows) {
        $tb->load([ "row $row", map { "r$row,c$_" } ( 1..$cols ) ]);
    }
    
    my $make_rule = sub {
        my ($args) = @_;
    
        my $left = $args->{left};
        my $right = $args->{right};
        my $main_left = $args->{main_left};
        my $middle = $args->{middle};
    
        return $tb->rule(
            sub {
                my ($index, $len) = @_;
    
                return ('─' x $len);
            },
            sub {
                my ($index, $len) = @_;
    
                my $char =
                    (     ($index == 0) ? $left
                          : ($index == 1) ? $main_left
                          : ($index == $num_cols+1) ? $right
                          : $middle
                    );
    
                return $char x $len;
            },
            );
    };
    
    my $start_rule = $make_rule->(
        {
            left => '┌',
            main_left => '╥',
            right => '┐',
            middle => '┬',
        }
        );
    
    my $mid_rule = $make_rule->(
        {
            left => '├',
            main_left => '╫',
            right => '┤',
            middle => '┼',
        }
        );
    
    my $end_rule = $make_rule->(
        {
            left => '└',
            main_left => '╨',
            right => '┘',
            middle => '┴',
        }
        );
    
    
    print $start_rule, $tb->title,
        (map { $mid_rule, $_, } $tb->body()), $end_rule;
    

    output

    perl table.pl 3 5
    ┌────────╥──────────┬──────────┬──────────┬──────────┬──────────┐
    │ Number ║ column 1 │ column 2 │ column 3 │ column 4 │ column 5 │
    ├────────╫──────────┼──────────┼──────────┼──────────┼──────────┤
    │row 1   ║r1,c1     │r1,c2     │r1,c3     │r1,c4     │r1,c5     │
    ├────────╫──────────┼──────────┼──────────┼──────────┼──────────┤
    │row 2   ║r2,c1     │r2,c2     │r2,c3     │r2,c4     │r2,c5     │
    ├────────╫──────────┼──────────┼──────────┼──────────┼──────────┤
    │row 3   ║r3,c1     │r3,c2     │r3,c3     │r3,c4     │r3,c5     │
    └────────╨──────────┴──────────┴──────────┴──────────┴──────────┘