PDSC用レシピ #5: さらに精巧なデータ構造

Tom Christiansen著
< tchrist@perl.com >

リリース 0.2 (テスト済み)
1995年10月2日(月)


さらに精巧なレコードの宣言:

異なった、いろいろなソートの対象となる複数のフィールドを持つ レコードの生成方法や使用方法を示したサンプルがここにあります。

    $rec = {
        STRING  => $string,
        LIST    => [ @old_values ],
        LOOKUP  => { %some_table },
        FUNC    => \&some_function,
        FANON   => sub { $_[0] ** $_[1] }, 
        FH      => \*STDOUT,
    };

    print $rec->{STRING};

    print $rec->{LIST}[0];
    $last = pop @ { $rec->{LIST} };

    print $rec->{LOOKUP}{"key"};
    ($first_k, $first_v) = each %{ $rec->{LOOKUP} };

    $answer = &{ $rec->{FUNC} }($arg);
    $answer = &{ $rec->{FANON} }($arg1, $arg2);

    # FH参照の外側のブロックブレースに注意
    print { $rec->{FH} } "a string\n";

    use FileHandle;
    $rec->{FH}->autoflush(1);
    $rec->{FH}->print(" a string\n");

混成レコードのハッシュの宣言:


    %TV = ( 
       "flintstones" => {
	   series   => "flintstones",
	   nights   => [ qw(monday thursday friday) ];
	   members  => [
	       { name => "fred",    role => "lead", age  => 36, },
	       { name => "wilma",   role => "wife", age  => 31, },
	       { name => "pebbles", role => "kid", age  =>  4, },
	   ],
       },

       "jetsons"     => {
	   series   => "jetsons",
	   nights   => [ qw(wednesday saturday) ];
	   members  => [
	       { name => "george",  role => "lead", age  => 41, },
	       { name => "jane",    role => "wife", age  => 39, },
	       { name => "elroy",   role => "kid",  age  =>  9, },
	   ],
	},

       "simpsons"    => { 
	   series   => "simpsons",
	   nights   => [ qw(monday) ];
	   members  => [
	       { name => "homer", role => "lead", age  => 34, },
	       { name => "marge", role => "wife", age => 37, },
	       { name => "bart",  role => "kid",  age  =>  11, },
	   ],
	},
     );

混成レコードのハッシュの生成:


    # ファイルからの読込
    # これは、ファイル自身を上記に示したの生データフォーマットの
    # 中に置いてしまう方法で非常に簡単に実行されます。perlは
    # データとして宣言されていれば喜んで混成レコードを構文解析
    # します。ですから、時折ですが,上記を実行するのは最も容易
    # ということになります。

    # ここでは一つずつ積み上げていきます。
    $rec = {};
    $rec->{series} = "flintstones";
    $rec->{nights} = [ find_days() ];

    @members = ();
    # このファイルの中身は field=value 文法となっていると仮定
    while () {
	%fields = split /[\s=]+/;
	push @members, { %fields };
    }
    $rec->{members} = [ @members ];

    # now remember the whole thing
    $TV{ $rec->{series} } = $rec;

    ###########################################################
    # さて、あなたはポインターを同じデータ構造の中に包含した、
    # 興味深い外部フィールドを作ってみたいと思われたかもしれません。
    # 例えば、複製レコードや更新の問題がない、kidsのレコードの
    # リストへの配列参照である{kids}フィールドです。それは、
    # ある部分を変更すれば、すべての箇所を変更してくれます。
    ###########################################################
    foreach $family (keys %TV) { 
	$rec = $TV{$family}; # 暫定ポインター 
	@kids = ();
	for $person ( @{$rec->{members}} ) {
	    if ($person->{role} =~ /kid|son|daughter/) {
		push @kids, $person;
	    }
	}
	# 銘記: $rec と $TV{$family} は同じデータを指している!!
	$rec->{kids} = [ @kids ];  
    }

    # あなたはリストをコピーしましたが,リスト自身はコピーされていない
    # オブジェクトへのポインターを含んでいます。
    # すなわち、bartに年を取らせたい場合,次のようにします。

    $TV{simpsons}{kids}[0]{age}++;

    # で,これはまた下記で変更されます。 
    print $TV{simpsons}{members}[2]{age};

    # なぜなら $TV{simpsons}{kids}[0] と $TV{simpsons}{members}[2]は両方とも
    # 潜在している同じ匿名ハッシュデーブルを指し示しているからです。
    # すべての内容をprint 
    foreach $family ( keys %TV ) {
	print "the $family";
	print " is on during @{ $TV{$family}{nights} }\n";
	print "its members are:\n";
	for $who ( @{ $TV{$family}{members} } ) {
	    print " $who->{name} ($who->{role}), age $who->{age}\n";
	}
	print "it turns out that $TV{$family}{'lead'} has ";
	print scalar ( @{ $TV{$family}{kids} } ), " kids named ";
	print join (", ", map { $_->{name} } @{ $TV{$family}{kids} } );
	print "\n";
    }


ご意見、ご要望は、 電子メールまたは 投稿にお願い致します。

ホームページへ戻る。