2

私は Perl はあまり得意ではありませんが、多次元配列で並べ替えを行う必要があります。概念をよりよく理解するためにいくつかのテスト コードを試してみましたが、近づいていると思いますが、魔法の組み合わせが見つかりません。

私ができないように見えるのは、配列を逆参照して正しく印刷することです。参照されている配列の値を除いて、これらの参照について知る必要がある世界のほぼすべてを取得できるようです。

タブ区切りのフラット ファイルからデータを取得しているので、サンプル コードでは、分割を介して複数の配列を作成し、それらを 1 つの配列にプッシュすることでそれを模倣しています。実際には、ファイルをループし、タブを分割して配列にプッシュします。

これについてもっと良い方法があれば、私はすべて耳にします。フラット ファイルの各行は 1 つのレコードです。最初に日付で並べ替えて、最も古いレコードを一番上に表示してから、2 番目の並べ替えを行ってアカウント番号でレコードをグループ化する必要があります。オンラインでいくつかの例を見てきましたが、模倣する必要があるデータで機能するように見えるものは見つかりませんでした。

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
}
4

3 に答える 3

5

まず第一に、常にuse strict;プログラムの先頭に配置する必要があります。これにより、多くのエラーが早期に検出されます。

foreachループの最後の行は、$thingy正しく逆参照する行です。ただし@{$thingy}、(文字列連結) 演算子の左側に配置したため.、配列はスカラー コンテキストにあり、スカラー コンテキストの配列はそのサイズに評価されます。言うだけ:

print "@{$thingy}\n";

@$thingyスペースで区切られた要素を取得する、または一般的に

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

縦棒文字など、別のセパレータを使用する場合。言うこともできます

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

セパレーターなしで要素を印刷します。

于 2011-05-23T22:07:35.683 に答える
3

@thingy宣言されておらず、未定義です(そして不要です)。

ネストされた 2 つのループを使用して

  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));

並べ替えに 2 つの基準が必要な場合 (最初のインデックスのプライマリ基準と 2 番目のインデックスのセカンダリ基準)、次のように記述できます。

my @sorted = sort { $a->[0] cmp $b->[0] 
                             ||
                    $a->[1] cmp $b->[1] 
                  } @array;
于 2011-05-23T22:14:39.020 に答える
2

最初に行う必要があるのは、これをスクリプトに追加することです。

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
}
于 2011-05-23T22:34:40.210 に答える