Как распечатать данные в виде столбца в Perl?

У меня есть программа, которая печатает содержимое массивов в строках. Я хотел бы, чтобы он печатал каждый массив в столбце рядом друг с другом.

Это код:

#!/usr/local/bin/perl

use strict;
use warnings;

my @M_array;
my @F_array;

open (my $input, "<", 'ssbn1898.txt');

while ( <$input> ) {

    chomp;

    my ( $name, $id ) = split ( /,/ ); 

    if ( $id eq "M" ) {
        push ( @M_array, $name );
    }
    else {
        push ( @F_array, $name ); 
    }
}
close ( $input );

print "M: @M_array \n"; 
print "F: @F_array \n";

Возможно ли это, или я пытаюсь сделать что-то, что невозможно сделать?

Желаемый формат:

M      F 
Namem1 Namef1 
Namem2 Namef2 

person mgb16    schedule 13.07.2015    source источник
comment
Добавление формата, который вы хотели бы использовать в качестве вывода, поможет получить более качественные ответы.   -  person Hunter McMillen    schedule 13.07.2015
comment
я бы хотел что-то вроде   -  person mgb16    schedule 13.07.2015
comment
M F Имяm1 Имяf1 Имяm2 Имяf2   -  person mgb16    schedule 13.07.2015


Ответы (6)


Вы можете добавить любой разделитель между своими данными, используя функцию join, пример ниже форматирует данные в вашем массиве, разделенные вкладками:

...
use List::MoreUtils qw/pairwise/;

my $separator = "\t";
print join($separator, qw(M F)), "\n";
print join(
   "\n", 
   pairwise { ( $a // '') . $separator . ( $b // '') } @M_array, @F_array
), "\n";
...
person Hunter McMillen    schedule 13.07.2015
comment
Возможно, стоит упомянуть, что // — это perl 5.10 и выше. 5.8.8 довольно старый, но, кажется, все еще в порядке! - person Sobrique; 13.07.2015

Я думаю, вам следует использовать форматы Perl. Ознакомьтесь с документацией по Perl. В вашем случае вы можете использовать поле формата @*.

Я расширил ваш код, чтобы напечатать желаемый результат в конце

use strict;
use warnings;

my @M_array;
my @F_array;

open (my $input, "<", 'ssbn1898.txt');

while ( <$input> ) {

    chomp;

    my ( $name, $id ) = split ( /,/ ); 

    if ( $id eq "M" ) {
        push ( @M_array, $name );
    }
    else {
        push ( @F_array, $name ); 
    }
}
close ( $input );

unshift @M_array, 'M';
unshift @F_array, 'F';

my $namem; 
my $namef;

my $max = 0;

$max = (length($_) gt $max  ? length($_) : $max) for @M_array;
my $w = '@' . '<' x $max;

eval "
format STDOUT = 
$w @*
\$namem, \$namef 
.
";

while ( @M_array or @F_array) {

    $namem = shift @M_array || '';
    $namef = shift @F_array || '';

    write;

}
person Hermann Schachner    schedule 13.07.2015
comment
Я думаю, что это было бы намного лучше с примером. - person Sobrique; 13.07.2015
comment
@Sobrique Perl format выглядит сложно (для программистов на C/C++). Вы когда-нибудь использовали его успешно? - person Wolf; 13.07.2015
comment
Лет 15 назад, да. Не с. (Что является частью того, почему я был увлечен примером :)) - person Sobrique; 13.07.2015
comment
@Sobrique: Обычно я не создаю вывод с выровненными столбцами в командной строке. Я бы предпочел создать структурированный вывод и позволить другой программе выполнить форматирование. Хммм... возможно, это был бы лучший ответ ;-) - person Hermann Schachner; 13.07.2015
comment
Что касается вашего замечания - возможно, вы могли бы сделать $namem = shift @M_array // '';, чтобы получить пустую строку, если она не определена. - person Sobrique; 13.07.2015
comment
Ничего себе, это работает :-) Но лучше добавить комментарий, что первый вывод не использует форматирование. Ах, есть проблема с отсутствующими данными? Я попробовал @m = ("a", "b"); @f = ("x", "y", "z"); и получил только 2 строки вывода. - person Wolf; 13.07.2015
comment
@Sobrique Спасибо за подсказку. - person Hermann Schachner; 13.07.2015
comment
@Wolf Да, я тоже обнаружил проблему и соответственно улучшил код. И я удалил операторы печати. - person Hermann Schachner; 13.07.2015

join, вероятно, является самым простым подходом к использованию tabs, который хорошо выровняет ваши столбцы.

join ( "\t", @array ),

Кроме того, Perl позволяет форматировать через (s)printf:

printf ( "%-10s %-10s", "first", "second" );

Или более подробный 'format'

Учитывая, что вы пытаетесь сделать, это поместить ваши два массива в столбцы:

#!/usr/local/bin/perl
use strict;
use warnings;

my $format = "%-10s\t%-10s\n";

my @M_array = qw ( M1 M2 M3 M4 M5 );
my @F_array = qw ( F1 F2 F3 );
my $maxrows = $#M_array > $#F_array ?  $#M_array : $#F_array; 

printf ( $format, "M", "F" );
for my $rownum ( 0..$maxrows ) { 
    printf ( $format, $M_array[$rownum] // '', $F_array[$rownum] // '' );

}

Это напечатает строку заголовка, а затем зациклит ваши массивы, печатая по одной строке за раз. // — это условная операция, которая проверяет, определено ли что-то. Однако он доступен только в новых perls*. В более старых версиях || поможет - это почти то же самое, но обработка '' и 0 немного отличается.

* Perl 5.10 и более поздние версии, так что это довольно безопасно, но стоит упомянуть, потому что некоторые системы все еще работают с Perl 5.8.

person Sobrique    schedule 13.07.2015
comment
printf, конечно, проще в использовании, чем комбинация print sprintf. Я получаю синтаксические ошибки, после исправления снова ошибки: Использование неинициализированного значения... может быть, мой Perl слишком старый (5.8.8)? - person Wolf; 13.07.2015
comment
да. // — это функция Perl 5.10. || будет работать в 5.8.8. И да, 5.8.8 действительно устарела — официально закончилась ее жизнь, так как она выпущена в 2008 году. (Но вы не единственный, кто использует его любым способом) - person Sobrique; 13.07.2015
comment
Хорошо, я запустил его с perl 5.8.8. Проблема с этим ответом в том, что подсветка синтаксиса SO его не понимает. Так что это читается совершенно запутанно. Может быть, было бы лучше добавить еще и ||. - person Wolf; 15.07.2015

Вы можете отформатировать вывод с помощью функции sprintf, но есть еще несколько проблем, которые необходимо решить: если массивы не имеют одинакового количества записей? Для этого вам понадобится заполнитель. Сколько букв должно поместиться в столбец? Как это должно быть выровнено? Некоторый код для иллюстрации:

#!/usr/bin/perl
use strict;
use warnings;

my @m = (1, 2, 3);
my @f = (11, 22, 33, 44);

# calculate how many rows to display
my $max = @m;
if (@m < @f) {
    $max = @f;
}

# placeholder for missing data
my $none = '-';

# formatting 20 chars per column, left aligned
my $fmt = "%-20s%-20s\n";

# print header
print sprintf($fmt, "M", "F");

# print data rows
foreach my $i (0..$max-1) {
    print sprintf($fmt, ($m[$i] or $none), ($f[$i] or $none));
}

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

person Wolf    schedule 13.07.2015

Заимствование у @HunterMcMillen

use strict;
use warnings;
use feature "say";

local $, = "\t";   # separator when printing list

my $i = (@F_array > @M_array) ? $#F_array : $#M_array;

say qw(M F);
say $M_array[$i] //"", $F_array[$i] //"" for 0 .. $i;
person mpapec    schedule 13.07.2015

Я предполагаю, что Text::Table - это необходимый модуль, который поставляется с дистрибутивом perl (просто нужно установить). Просмотрите приведенную ниже документацию -

Документация Text::Table

Вам нужно передать содержимое в виде массива методу add(), и он сотворит для вас чудеса.

person CodeQuestor    schedule 15.07.2015