Я не могу разыменовать массив правильно - PullRequest
2 голосов
/ 24 мая 2011

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

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

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

Если есть лучший способ сделать это, я весь в ушах. Каждая строка в плоском файле является отдельной записью. Мне нужно сначала отсортировать по дате, чтобы получить самые старые записи, а затем выполнить вторичную сортировку, чтобы сгруппировать записи по номеру действия. Я просмотрел несколько примеров в Интернете, но не нашел ничего, что могло бы работать с данными, которые мне нужно имитировать.

my @s1 = split(/:/, 'X:Y:Z');
my @s2 = split(/:/, 'A:B:C');
my @s3 = split(/:/, 'Q:L:P:0');
my @s4 = split(/:/, 'U:E:G');

my @array = ();
push(@array, \@s1);
push(@array, \@s2);
push(@array, \@s3);
push(@array, \@s4);

print "@array\n";

my @sorted = sort { $a->[0] cmp $b->[0] } @array;

print "\n";
foreach $thingy (@sorted)
{
    print @thingy . "\n"; #result: number 0
    print $thingy . "\n"; #result: reference
    #print ${$thingy} . "\n"; #result: 'Not a scalar reference' error
    print ${@thingy} . "\n"; #result: file name (???)
    print @{$thingy} . "\n"; #result: length of the array referenced
}

Ответы [ 3 ]

5 голосов
/ 24 мая 2011

Прежде всего, вы всегда должны ставить use strict; в начале вашей программы. Это рано поймает многочисленные ошибки.

Последняя строка в вашем цикле foreach - это строка, которая правильно разыменовывает $thingy. Но поскольку вы поместили @{$thingy} слева от оператора . (конкатенация строк), массив находится в скалярном контексте, а массивы в скалярном контексте оцениваются по их размеру. Просто скажи:

print "@{$thingy}\n";

чтобы получить элементы @$thingy, разделенные пробелами, или вообще

print join('|', @{$thingy}), "\n";

если вы хотите использовать другой разделитель, например символ вертикальной черты. Вы также можете просто сказать

print @{$thingy}, "\n";

чтобы напечатать элементы без разделителя.

3 голосов
/ 24 мая 2011

@thingy не объявлено и не определено (и не нужно).

Используйте две вложенные петли для

  1. итерация по вашему массиву со ссылками на массив
  2. и затем в каждом цикле перебирайте элементы в указанном массиве.

Как это

foreach my $array_ref (@sorted)
{
    foreach my $item (@{$array_ref}) {
        print $item, ",";
    }
    print "\n";
}

Выражение @{$array_ref} будет разыменовывать ссылку на ваш массив. Тогда он используется как массив.

Дополнительно:

Вы можете заменить

my @s1 = split(/:/, 'X:Y:Z');
my @s2 = split(/:/, 'A:B:C');
my @s3 = split(/:/, 'Q:L:P:0');
my @s4 = split(/:/, 'U:E:G');

my @array = ();
push(@array, \@s1);
push(@array, \@s2);
push(@array, \@s3);
push(@array, \@s4);

с

my @array = ();
push(@array, map { [split(/:/, $_)] } qw(X:Y:Z A:B:C Q:L:P:0 U:E:G));

Если для сортировки нужны два критерия (первичный по первому индексу и вторичный по второму индексу), это можно записать так:

my @sorted = sort { $a->[0] cmp $b->[0] 
                             ||
                    $a->[1] cmp $b->[1] 
                  } @array;
2 голосов
/ 24 мая 2011

Первое, что вам нужно сделать, это добавить это в ваш скрипт:

use strict;
use warnings;

Тогда вы получите предупреждение:

Global symbol "@thingy" requires explicit package name

Это означает, что @thingy не определено. В perl $thingy и @thingy считаются отдельными переменными.

Другой способ создания вашего массива - использовать анонимные массивы, например:

push @array, [ split(/:/, 'X:Y:Z') ];
push @array, [ split(/:/, 'A:B:C') ];
...

Тогда вам не придется создавать одноразовые переменные. Или с файлом, подобным описанному вами (\t - вкладка):

while (<>) {
    push @array, [ split /\t/, $_ ];
}

Способ сортировки по нескольким столбцам из perlmonks:

my @a = ([1,2], [3,4]);
my @b = sort {

    $a->[0] <=> $b->[0] || # the result is -1,0,1 ...
    $a->[1] <=> $b->[1]    # so [1] when [0] is same

} @a;

http://www.perlmonks.org/index.pl?node_id=674374

Конечно, это предполагает числовые значения в ваших полях. В противном случае используйте cmp.

Для печати:

for my $ref (@array) {
    my $i = 0;
    for my $value (@$ref) {
        print $value; 
        print "," if ($i++ < $#$ref); # comma delimited
    }
    print "\n"; # end of record
}
...