ishiducaの日記 このページをアンテナに追加 RSSフィード

2009-09-07

[][][]リファレンスを使ってデータを構造化する 21:06 リファレンスを使ってデータを構造化する - ishiducaの日記 を含むブックマーク はてなブックマーク - リファレンスを使ってデータを構造化する - ishiducaの日記 リファレンスを使ってデータを構造化する - ishiducaの日記 のブックマークコメント

カテゴリー、摘要、金額の順にスペースで区切られたファイル(data.txt)を読み込み、構造的なハッシュテーブルを作ります。

data.txt

その他    両替手数料                     100
移動費    乗車券(直江津〜東京都区内)    4840
移動費    特急指定券(直江津〜越後湯沢)  1220
移動費    新幹線自由券(越後湯沢〜東京)  2720
飲料      水(2l)                         178
菓子      ベビースター                   118
食事      四川風麻婆豆腐丼               450
駐車      駐車料金                       300
食事      寿司食べ放題+飲み放題         5000
宿泊      宿泊費                        4800
宅配便    宅配便の箱                     300
宅配便    送料                          1200
食事      親子丼                         470
移動費    乗車券(東京駅構内〜高田)      4840
移動費    新幹線自由席(東京〜越後湯沢)  2720
移動費    特急指定席(越後湯沢〜高田)    1120
飲料      アイスカフェラテ               300
デザート  ラムレーズンのアイス           300

ハッシュ(%ls)のキーはカテゴリー(その他、移動費など)、値は摘要と金額で構成された配列を値とした配列とします。...と言ってもわかりにくいので、先にハッシュテーブルを見ましょう。今回書いたスクリプト(dump.pl)を実行すると表示されます。

$VAR1 = {
          'デザート' => [
                              [
                                'ラムレーズンのアイス', '300'
                              ]
                            ],
          '食事' => [
                        [
                          '四川風麻婆豆腐丼', '450'
                        ],
                        [
                          '寿司食べ放題+飲み放題', '5000'
                        ],
                        [
                          '親子丼', '470'
                        ]
                      ],
          'その他' => [
                           [
                             '両替手数料','100'
                           ]
                         ],
          '菓子' => [
                        [
                          'ベビースター', '118'
                        ]
                      ],
          '飲料' => [
                        [
                          '水(2l)','178'
                        ],
                        [
                          'アイスカフェラテ','300'
                        ]
                      ],
          '移動費' => [
                           [
                             '乗車券(直江津〜東京都区内)','4840'
                           ],
                           [
                             '特急指定券(直江津〜越後湯沢)','1220'
                           ],
                           [
                             '新幹線自由券(越後湯沢〜東京)', '2720'
                           ],
                           [
                             '乗車券(東京駅構内〜高田)','4840'
                           ],
                           [
                             '新幹線自由席(東京〜越後湯沢)','2720'
                           ],
                           [
                             '特急指定席(越後湯沢〜高田)','1120'
                           ]
                         ],
          '駐車' => [
                        [
                          '駐車料金', '300'
                        ]
                      ],
          '宿泊' => [
                        [
                          '宿泊費', '4800'
                        ]
                      ],
          '宅配便' => [
                           [
                             '宅配便の箱', '300'
                           ],
                           [
                             '送料','1200'
                           ]
                         ]
        };

dump.pl

#!/usr/bin/perl -wnlaF'\s+'
use strict;
use Data::Dumper;

our(%ls);
BEGIN{
    $ARGV[0] = 'data.txt';
}

my $category = shift @F;
# exists $ls{$category} or $ls{$category} = [];
push @{$ls{$category}}, [@F];

END{
    print Dumper(\%ls);
    exit 0;
}

今回はデータ構造を見るだけでしたが、これで応用の効くデータ構造ができました

トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20090907

2009-06-01

[][]「リファレンスを使ってネストしたデータ構造を作る」を改造する 16:44 「リファレンスを使ってネストしたデータ構造を作る」を改造する - ishiducaの日記 を含むブックマーク はてなブックマーク - 「リファレンスを使ってネストしたデータ構造を作る」を改造する - ishiducaの日記 「リファレンスを使ってネストしたデータ構造を作る」を改造する - ishiducaの日記 のブックマークコメント

前回は多重配列(配列に配列)を作った。今回はハッシュに配列を格納する。


点数を記録したファイル

$ cat score.tsv
score  1st 2nd 3rd
jiji   12  64  33
baba   22  32  67
child  88  76  21

2行目以降では、最初のデータが名前、2番目以降が実際の点数なので、名前をキーにして値の代わりに無名配列を格納する

#!/usr/bin/perl -wnlaF'\t'
use strict;

our(%score,@title);

BEGIN{
    $ARGV[0] = 'score';
}

# 1行目はヘッダ列なので
if( $. == 1 ){
    @title = (@F,"sum");
}
# 2行目以降をハッシュ %score にデータを格納する
else {
    my $name = shift @F;  # 各行の最初のデータをキーに
    $score{$name} = [@F]; # 2番目以降のデータを無名配列に格納
}

END{
    {
        local $, = "\t";
        print @title;
    }
    foreach my $name ( sort keys %score ){
        my $sum = 0;
        printf "$name\t";
        foreach my $point ( @{$score{$name}} ){
            printf "$point\t";
            $sum += $point;
        }
        print $sum;
    }
    exit 0;
}

実行結果

$ perl nest2.pl
score   1st 2nd 3rd sum
baba    22  32  67  121
child   88  76  21  185
jiji    12  64  33  109

ハッシュも多重配列のとき同様、$score を使ってみる

#!/usr/bin/perl -wnlaF'\t'
use strict;

our($score,@title);

BEGIN{
    $ARGV[0] = 'score';
}

if( $. == 1 ){
    @title = (@F,"sum");
} else {
    my $name = shift @F;
    $score->{$name} = [@F];
}

END{
    {
        local $, = "\t";
        print @title;
    }
    foreach my $name ( sort keys %$score ){
        my $sum = 0;
        printf "$name\t";
        foreach my $point ( @{$score->{$name}} ){
            printf "$point\t";
            $sum += $point;
        }
        print $sum;
    }
    exit 0;
}

[][]リファレンスを使ってネストしたデータ構造を作る 14:43 リファレンスを使ってネストしたデータ構造を作る - ishiducaの日記 を含むブックマーク はてなブックマーク - リファレンスを使ってネストしたデータ構造を作る - ishiducaの日記 リファレンスを使ってネストしたデータ構造を作る - ishiducaの日記 のブックマークコメント

リファレンスを利用して入れ子の配列を作れば、データ管理が楽(かも)

例えば、下のような点数を記録したファイル(score.tsv)を扱う場合

$ cat score.tsv
score  1st 2nd 3rd
jiji   12  64  33
baba   22  32  67
child  88  76  21

配列@scoreに無名の配列にデータを格納して、それを格納する。

#!/usr/bin/perl -wnlaF'\t'
use strict;

our(@score);

BEGIN{
    $ARGV[0] = 'score';
}

push @score, [ @F ];

END{
    print $score[0]->[1];
    $, = "\t";
    print @{$score[2]};
    exit 0;
}

実行結果

$ perl nest.pl
1st
baba    22    32    67

push @socre, [ @F ]; を

push @score, @F;

のように [] を使わないでやると失敗する。


これも同じ。@scoreの代わりに$scoreを使う

#!/usr/bin/perl -wnlaF'\t'
use strict;

our($score);

BEGIN {
    $ARGV[0] = 'score';
}

push @$score, [ @F ];

END {
    print $score->[0]->[1];
    $, = "\t";
    print @{$score->[2]};
    exit 0;
}

正直ごちゃごちゃしてて、分りにくいと感じてしまう。慣れていないせいなのか、書き方が悪いのか。まだ理解が不足してるんだろうな

トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20090601