「続・初めての Perl」勉強2日目

若干間が空いてしまったが、また今日から再開だー。

第四章 リファレンス入門

さっぱりだ。あとこの本だけじゃなく、リファレンスに関するサイトを見ても「C のポインタみたいなもの」って表現は意味がないと思う。C が出来る人は Perl なんてあっさりだろうし、C が出来ない(もしくは知らない)人からしたらそれが何の意味があるのか分からない。
ラクダ本で一番気になるのがそうした「例え話で C を持ってくる」こと。誰もが C 言語を知ってると思うな!

練習問題1


次の式のうち異なる参照先はいくつあるでしょうか。

$ginger->[2][1]
${$ginger[2]}[1]
$ginger->[2]->[1]
${$ginger->[2]}[1]

${$ginger[2]}[1] と $ginger->[2]->[1] は同じかな?
それ以外は違うと思う。たぶん。あんまし自信ない。

練習問題2

check_required_items の最終バージョンを活用して、引数としてハッシュリファレンスだけを取る check_items_for_all サブルーチンを書いてください。ハッシュリファレンスが指すハッシュのキーは Minnow 号の搭乗者、値は彼らが船内に持ち込もうとしている持ち物配列へのリファレンスとします。
新しいサブルーチンは、ハッシュ内の1人1人について check_required_items を呼び出し、必須アイテムが入るように持ち物配列を書き換えるものとします。

ハッシュリファレンスだけを取るってなんだ。

#!/usr/local/bin/perl -w

my @gilligan = qw / blue_shirt hat jacket perserver sunscreen /;
my @skipper = qw / sunscreen water_bottle slide_rule batteries radio /;
my @professor = qw / red_shirt hat lucky_socks water_bottle /;
my %all = (
    Gilligan => \@gilligan,
    Skipper => \@skipper,
    Professor =>@professor,
);

check_items_for_all(\%all);

sub check_items_for_all {
    my $all = shift;
    for my $person (sort keys %$all) {
        check_required_items($person, $all->{$person});
    }
}

sub check_required_items {
    my $who = shift;
    my $items = shift;
    my @required = qw / preserver sunscreen water_bottle jacket /;
    my @missing = ();
    for my $item (@required) {
        unless (grep $item eq $_, @$items) {
            print "$who is missing $item.\n";
            push @missing, $item;
        }
    }
    if (@missing) {
        print "Adding @missing to @$items for $who.\n";
        push @$items, @missing;
    }
}

これでハッシュリファレンスが取れるのか。そもそもサブルーチンの中でサブルーチンが実行されるとどうなのかがあんまし想像つかない。

第五章 リファレンスとスコープ

練習問題1


実行せずに、このプログラムのまずいところが分かりますか。1,2分しても問題点が分からないようなら、実行できるかどうか試してみると、直し方のヒントが得られるはずです。

my %passenger1 {
    name => 'Ginger',
    age => 22,
    occupation => 'Movie Star',
    real_age => 35,
    hat => undef,
};

my %passenger2 {
    name => 'Mary Ann',
    age => 19,
    hat => 'bonnet',
    favorite_food => 'corn',
};

my @passengers = (\%passenger1, \%passenger2);

中かっこじゃなくて丸かっこと?
まずいってのがシンタックスエラーなのか、ただ単に美しくないってだけなのか、その辺がよく分からん。

練習問題2

Professor のデータファイルは、 coconet.dat という名前に含まれています。(オライリー Web サイトからダウンロード:http://www.oreilly.co.jp/book/4873113059/)コメント行が含まれていますので、必ず読み飛ばしてください。
出力の各ソースマシンの部分でそのマシンが転送したバイトの合計が表示されるようにしてください。そして、転送データの多いものから順にソースマシンが並ぶようにしてください。ソースマシングループ内では、ソースマシンからの転送料の多いものから順にデスティネーションマシンが並ぶようにしてください。
出力は、最も多くのデータを送ったソースマシンがリストの先頭に並び、そのソースから最も多くのデータを受け取ったデスティネーションがその中の先頭に並ぶようにします。

できそうでできない。。。ちょっとがんばってみる。明日になっても出来なかったら諦める。。。

my $all ="**all machines**";

my %total_bytes;
while (<>) {
    next if /^#/;
    my ($source, $destination, $bytes) = split;
    $total_bytes{$source}{$destination} += $bytes;
    $total_bytes{$source}{$all} += $bytes;
}

my @sources = sort { $total_bytes{$b}{$all} <=> $total_bytes{$a}{$all} } keys %total_bytes;

for my $source (@sources) {
    print "$source: $total_bytes{$source}{$all} total bytes sent\n";
    my @destinations =
        sort { $total_bytes{$source}{$b} <=> $total_bytes{$source}{$a} } keys %{ $total_bytes{$source} };
    for my $destination (@destinations) {
        next if $destination eq $all;
        print "  $source => $destination:",
            " $total_byets{$source}{$destination} bytes\n";
    }
    print "\n";
}

めっちゃ考え抜いたけど、結局各ソースマシンごとの転送バイトの合計を出すのが分からなくてギブアップした。
そもそもファイルを読み込んでやるって方法じゃないのか?