Как распечатать Perl 2-мерный массив?

Я пытаюсь записать простой сценарий Perl, который читает *.csv, помещает строки *.csv файла в двумерной матрице, и затем печатает на объекте из массива и затем печатает строку массива.

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

open(CSV, $ARGV[0]) || die("Cannot open the $ARGV[0] file: $!");
my @row;
my @table;

while(<CSV>) {
        @row = split(/\s*,\s*/, $_);
        push(@table, @row);
}
close CSV || die $!;

foreach my $element ( @{ $table[0] } ) {
    print $element, "\n";
}

print "$table[0][1]\n";

Когда я запускаю этот скрипт, я получаю следующую ошибку, и ничто не печатает:

Не может использовать строку ("1") в качестве МАССИВА касательно в то время как "строгие судьи", используемые в./scripts.pl строке 16.

Я посмотрел на многих других форумах, и все еще не уверено, как устранить эту проблему. Кто-либо может помочь мне исправить этот сценарий?

8
задан Matt Pascoe 10 June 2010 в 21:36
поделиться

6 ответов

Вы не создаете двумерный массив (AoA или «Массив массивов» на языке Perl). Эта строка:

push(@table, @row);

добавляет данные из @row в @table .Вместо этого вам нужно вставлять ссылку и создавать новую переменную каждый раз в цикле, чтобы вы не нажимали одну и ту же ссылку повторно:

my @table;
while(<CSV>) {
    my @row = split(/\s*,\s*/, $_);
    push(@table, \@row);
}

Хотя использование split подходит для тривиальных файлов CSV, это ужасно непригоден ни для чего другого. Вместо этого используйте модуль типа Text :: CSV_XS :

use strict;
use warnings;
use Text::CSV_XS;

my $csv  = Text::CSV_XS->new() or die "Can't create CSV parser.\n";
my $file = shift @ARGV         or die "No input file.\n";
open my $fh, '<', $file        or die "Can't read file '$file' [$!]\n";

my @table;
while (my $row = $csv->getline($fh)) {
    push @table, $row;
}
close $fh;

foreach my $row (@table) {
    foreach my $element (@$row) {
        print $element, "\n";
    }
}

print $table[0][1], "\n";
10
ответ дан 5 December 2019 в 09:24
поделиться

Если вы вызываете push с аргументами списка, вы добавляете первый список с оставшимися списками в стеке. Читайте о push на Perldoc . Итак, ваш вызов push (@table, @row); создает более длинный список @table , а не двумерный массив.

Вы получили несколько сообщений, в которых добавление ссылки на список @row как \ @ row приведет к созданию списка строк, и это действительно работает. Я стараюсь делать это немного по-другому. Конечно, с Perl всегда есть другой способ сделать это!

Синтаксически вы также можете вставить ссылку на анонимный массив в скалярный элемент списка, чтобы создать многомерный список. Самое важное, что нужно знать о ссылках в Perl: 1) они являются скалярами и 2) они могут ссылаться на что угодно в Perl - код, массив, хэш, другую ссылку. Потратьте некоторое время на Perl Ref Tutorial , и это станет более понятным.С помощью кода просто добавьте [] вокруг элемента, который должен быть вторым измерением в вашем списке, поэтому push (@table, @row); должно быть push (@table, [@row]); В том же смысле вы помещаете [] вокруг вашего разделения, так что он становится push (@table, [split (/ \ s * , \ s * /, $ _)]); Это одновременно выполнит разбиение и создаст анонимный массив для результата.

Конкретная проблема, которая у вас есть, как создать многомерный список и получить к нему доступ, также очень хорошо рассматривается в учебнике Тома Кристенсена perllol . Решения ваших конкретных проблем с вашим кодом непосредственно рассматриваются здесь. .

Переписав свой код точным кодом из примера Тома на perllol, он станет таким:

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

my (@row, @table, $n, $rowref);

while(<DATA>) {
        chomp;
        # regex to separate CSV (use of a cpan module for CSV STRONGLY advised...
        @row = /(?:^|,)("(?:[^"]+|"")*"|[^,]*)/g;
        for (@row) {
            if (s/^"//) { s/"$//; s/""/"/g; }
        }
        push(@table, [ @row ]); #Note the [ ] around the list
}

# Now the table is created, print it:
my $rowcnt=0;
foreach $rowref (@table) {
    print "row $rowcnt:\n";
    $rowcnt++;
    print "  [ @$rowref ], \n";
}   

# You can access the table in the classic [i][j] form:
for my $i ( 0 .. $#table ) {
    $rowref = $table[$i];
    $n = @$rowref - 1;
    for my $j ( 0 .. $n ) {
        print "element $i, $j of table is $table[$i][$j]\n";
    }
}

# You can format it:
for my $i ( 0 .. $#table ) {
    print "$table[$i][0] $table[$i][1]\n";
    print "$table[$i][2]\n";
    print "$table[$i][3], $table[$i][4] $table[$i][5]\n\n";
}


__DATA__
Mac,Doe,120 jefferson st.,Riverside, NJ, 08075
Jack,McGinnis,220 hobo Av.,Phila, PA,09119
"John ""Da Man""",Repici,120 Jefferson St.,Riverside, NJ,08075
Stephen,Tyler,"7452 Terrace ""At the Plaza"" road",SomeTown,SD, 91234
,Blankman,,SomeTown, SD, 00298
"Joan ""Joan, the bone""",Jett,"9th, at Terrace plc",Desert City,CO,00123
2
ответ дан 5 December 2019 в 09:24
поделиться

Вам нужно 2 изменения:

  1. использовать локальную переменную для строки
  2. использовать ссылки для массива, который вы помещаете в @table

Итак, ваша программа должна выглядеть так:

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

open(CSV, $ARGV[0]) || die("Cannot open the $ARGV[0] file: $!");
my @table;

while(<CSV>) {
    my @row = split(/\s*,\s*/, $_);
    push(@table, \@row);
}
close CSV || die $!;

foreach my $element ( @{ $table[0] } ) {
    print $element, "\n";
}

print "$table[0][1]\n";       
2
ответ дан 5 December 2019 в 09:24
поделиться

Возможно, это то, что вам действительно нужно:

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

open(CSV, $ARGV[0]) || die("Cannot open the $ARGV[0] file: $!");
my @table;

while(<CSV>) {
        my @row = split(/\s*,\s*/, $_);
        push(@table, \@row);
}
close CSV || die $!;

foreach my $element ( @{ $table[0] } ) {
    print $element, "\n";
}

print "$table[0][1]\n";
1
ответ дан 5 December 2019 в 09:24
поделиться

Изменить

#push(@table, @row);
push(@table, \@row);  #push a reference to the array into each cell in @table.

Затем распечатывается ОК.

0
ответ дан 5 December 2019 в 09:24
поделиться
my @arr = ( [a, b, c],
            [d, e, f],
            [g, h, i],
          );

for my $row (@arr) {
    print join(",", @{$row}), "\n";
}

отпечатки

a,b,c
d,e,f
g,h,i

Редактировать: Я позволю другим получить признание за то, что они поймали неправильный толчок.

3
ответ дан 5 December 2019 в 09:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: