Многомерный массив, отформатированный в консольную сетку / столбцы - PullRequest
0 голосов
/ 30 апреля 2018

Используя Text :: Table или Text :: ANSITable, или что-то подобное ...

Если у меня есть двумерный массив (который представляет собой сетку данных), где первая строка может быть заголовком столбца, как я могу применить эти данные и отформатировать их в сетку командной строки со столбцами.

Примерно так: PERL: Как создать таблицу из массива?

За исключением того, что количество строк и столбцов является переменным в зависимости от настройки массива и должно автоматически выводиться как таковое.

Спасибо

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Хотя модули предлагают более простое управление и функции, если вам нужно только распечатать их в виде сетки

use warnings;
use strict;
use feature 'say';

my @ary = ([1..3], [10..12], [100..102]);

foreach my $row (@ary) { 
    printf "%7.3f  ", $_ for @$row; 
    say ''
}

Печать

  1.000    2.000    3.000  
 10.000   11.000   12.000  
100.000  101.000  102.000  

Выберите ваш спецификатор (%7.3f выше) в зависимости от того, какие данные у вас есть. Смотри sprintf

Если в первой строке есть заголовки, shift выводится из массива и печатается с той же шириной, но с использованием %s

my @ary = ([qw(one two three)], [1..3], [10..12], [100..102]); 

printf "%7s  ", $_ for @{shift @ary};
say '';

foreach my $row (@ary) { 
    printf "%7.3f  ", $_ for @$row; 
    say ''
}

Печатается так же, как указано выше, но с (выровненными) именами столбцов в первой строке.

Если « сетка данных » означает числовые данные, то код может обнаружить, существует ли строка заголовка, с разумным предположением, что первая строка содержит что-то нечисловое

use List::Util qw(any);

my $have_header = any { /[^0-9.+-]/ } @{$ary[0]};

, что также предполагает отсутствие NaN и 1e02 или что-то подобное в первой строке.

Еще лучше, используйте looks_like_number из Scalar :: Util

use List::Util qw(any);
use Scalar::Util qw(looks_like_number);

my $have_header = any { not looks_like_number($_) } @{$ary[0]};

Здесь используется внутренний смысл Perl того, что число равно , и, среди прочего, учитывается NaN и экспоненциальная запись.


Если программе необходимо определить ширину столбцов или они сильно различаются, для приятного вывода есть еще что сделать, поскольку нам нужна максимальная ширина каждого столбца.

use warnings;
use strict;
use feature 'say';    
use List::Util qw(max);

my $file = shift @ARGV || 'data.txt';
open my $fh, '<', $file or die "Can't open $file: $!";
my @ary = map { [ split ] } <$fh>;

my @maxw = (1) x @{$ary[0]};   
for my $r (@ary) {
    for (0..$#$r) {
        my $len = length $r->[$_];
        $maxw[$_] = $len if $len > $maxw[$_]
    }
};

my $hdr = shift @ary;
printf "%$maxw[$_]s  ", $hdr->[$_] for 0..$#$hdr;
say '';

for my $i (0..$#ary) {
    printf "%$maxw[$_].2f  ", $ary[$i]->[$_] for 0..$#{$ary[$i]};
    say '';
}

Ожидаются цифры, кроме заголовка. Несколько других разумных предположений сделаны.

С входным data.txt файлом, используемым для заполнения массива

one      two      three  
1.12   1.1   12  
1.00  10.00  102.000

программа печатает

 one    two    three  
1.12   1.10    12.00  
1.00  10.00   102.00  

Примечание. Если числа вычисляются в программе, эти скаляры используются в качестве чисел, и длина строки, представляющей их в печати, должна запрашиваться как length sprintf "%s", $num. Когда они читаются из файла, они воспринимаются как строки, что для простоты используется выше.

0 голосов
/ 30 апреля 2018

Вы можете использовать Text :: Table для этого, так как он обрабатывает переменное число строк и столбцов. Хотя документация оставляет желать лучшего, вы обычно можете посмотреть тестовые файлы или примеры, чтобы показать вам, как на самом деле должна использоваться библиотека. Я адаптировал example.pl , чтобы проиллюстрировать это:

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;

выход

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     │
└────────╨──────────┴──────────┴──────────┴──────────┴──────────┘
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...