Perlのプログラムについての質問です。

ランダムに選んだファイル10個の内容を、配列の配列に記憶するため、次のようなプログラムを書いています。
ほとんど同じ内容を10回繰り返し書いているので、非常に見づらいと感じています。
for文などを使って、すっきりさせたいのですが、配列の配列やリファレンスの扱い方がわからず、うまくできません。
すっきりさせる書き方があれば教えてください。
配列の配列(下記例では@DataArray)のデータ構造や形式は元の形でなくてもかまいません。
配列の配列である必要もありません。
よろしくお願いします。

$r = int(rand(@FileNameArray));
$FileName = $FileNameArray[$r];
open( DATA_01_H, $FileName );
@Data01 = <DATA_01_H>;
close DATA_01_H;
push @DataArray, \@Data01;
: :
(02~09まで繰り返し)
: :
$r = int(rand(@FileNameArray));
$FileName = $FileNameArray[$r];
open( DATA_10_H, $FileName );
@Data01 = <DATA_10_H>;
close DATA_10_H;
push @DataArray, \@Data10;

回答の条件
  • 1人5回まで
  • 登録:2008/03/17 22:43:58
  • 終了:2008/03/18 00:52:01

ベストアンサー

id:tkyk3 No.1

tkyk3回答回数59ベストアンサー獲得回数62008/03/17 23:18:39

ポイント120pt

foreach構文を使って、0から9の繰り返し(1..10でもいいですが…)でループを回し、@DataArray配列の中に配列としてデータを収めるというので如何でしょうか。

my @DataArray;
foreach (0..9) {
  my $r = int(rand(@FileNameArray));
  my $FileName = $FileNameArray[$r];
  open( DAT, $FileName );
  my @Data = <DAT>;
  close DAT;
  push (@DataArray, \@Data);
}

希望の構造があれば、またコメントでもしようかと思います。

id:uta_at_home

回答ありがとうございます。

これでいけるのなら、完璧に私の希望通りです。


素人な質問で申し訳ないのですが、この場合 @Dataを使い回すことで内容が上書きされないのでしょうか?

リファレンスは、Cで言うポインタのようなものと解説されていたので、@Dataを使い回すと同じメモリ領域にデータが上書きされてしまうのではないかと心配していました。

あるいは、毎度

my @Data = <DAT>;

と my宣言することで、毎度違うデータ領域が取られているのでしょうか?


もしよければ、この質問にも再度お答え頂けないでしょうか?

追加質問なので、コメントではなく回答で返信いただけるとありがたいです。

あつかましいですが、よろしくお願いします。


【追記】

メモリ領域が云々というのがめんどくさければ、「とにかくこれで上書きされずにちゃんと動くよ」という回答でもOKです。

よろしくお願いします。


【再追記】

追加質問の方は、haruo-31さん、iu43lkjds32さんがコメント欄で答えてくださいました。

私の知りたいことが全部解決したので、質問を終了させて頂きます。

ありがとうございました。m(_"_)m

2008/03/18 00:48:19

その他の回答(3件)

id:tkyk3 No.1

tkyk3回答回数59ベストアンサー獲得回数62008/03/17 23:18:39ここでベストアンサー

ポイント120pt

foreach構文を使って、0から9の繰り返し(1..10でもいいですが…)でループを回し、@DataArray配列の中に配列としてデータを収めるというので如何でしょうか。

my @DataArray;
foreach (0..9) {
  my $r = int(rand(@FileNameArray));
  my $FileName = $FileNameArray[$r];
  open( DAT, $FileName );
  my @Data = <DAT>;
  close DAT;
  push (@DataArray, \@Data);
}

希望の構造があれば、またコメントでもしようかと思います。

id:uta_at_home

回答ありがとうございます。

これでいけるのなら、完璧に私の希望通りです。


素人な質問で申し訳ないのですが、この場合 @Dataを使い回すことで内容が上書きされないのでしょうか?

リファレンスは、Cで言うポインタのようなものと解説されていたので、@Dataを使い回すと同じメモリ領域にデータが上書きされてしまうのではないかと心配していました。

あるいは、毎度

my @Data = <DAT>;

と my宣言することで、毎度違うデータ領域が取られているのでしょうか?


もしよければ、この質問にも再度お答え頂けないでしょうか?

追加質問なので、コメントではなく回答で返信いただけるとありがたいです。

あつかましいですが、よろしくお願いします。


【追記】

メモリ領域が云々というのがめんどくさければ、「とにかくこれで上書きされずにちゃんと動くよ」という回答でもOKです。

よろしくお願いします。


【再追記】

追加質問の方は、haruo-31さん、iu43lkjds32さんがコメント欄で答えてくださいました。

私の知りたいことが全部解決したので、質問を終了させて頂きます。

ありがとうございました。m(_"_)m

2008/03/18 00:48:19
id:iu43lkjds32 No.2

iu43lkjds32回答回数18ベストアンサー獲得回数02008/03/17 23:22:36

ポイント120pt

@Data01から@Data10を別に使うのでなければ,以下のように書き換えていけます。

1.

@Data01から@Data10を全て @Data00 に,

DATA_01_H から DATA_10_H を全て DATA_00_H に書き換える

2.

上記の書き換えたプログラムは10回同じことを繰り返しているので,

for で10回まわすように書き換えられる

同じファイルハンドルと配列を使い回しても大丈夫なはずです。

id:uta_at_home

回答ありがとうございます。

私もファイルハンドルや配列を使い回すことを考えていたのですが、リファレンスを使って配列の配列を作る際、配列のメモリ領域が上書きされてしまうのではないかと心配だったのです。

2008/03/18 00:18:26
id:haruo-31 No.3

haruo-31回答回数80ベストアンサー獲得回数102008/03/17 23:55:48

ポイント120pt

今回は何がしたいのか、ちょっと分からなかった&酔ってるので、

こんな感じでヒントになるでしょうか。

Perlは多次元配列について、勝手に配列を作って関連付けてくれます。

use strict;
use warnings;

my @array;

foreach my $a ( 0 .. 9 ) {
	foreach my $b ( 0 .. 9 ) {
		$array[$a][$b]=$a.$b;
	}
}

map { print join(",",@{$_})."\n"; } @array;


id:uta_at_home

ありがとうございます。

コメント欄でも丁寧かつ親切な回答を頂き、ありがとうございます。

m(_"_)m

2008/03/18 00:36:44
id:tkyk3 No.4

tkyk3回答回数59ベストアンサー獲得回数62008/03/18 00:48:30

ポイント20pt

皆さんの意見通りかと存じます。(既に解決済みかと思うのでコメントにしました)

一応、しゃしゃり出ておきます(^^;

id:uta_at_home

ありがとうございます。m(_"_)m

2008/03/18 00:50:43
  • id:haruo-31
    あー、しまった。
    tkyk3さんの意見と被ってるのでオープンしなくていいです。

    なんか書き方からして、学校の授業ですか?
  • id:iu43lkjds32
    再利用のときのゴミが心配であれば,毎回ループの中でundef を使って消すか,{} で範囲を絞ってmy を使ってスコープを局所化してみてください。
  • id:haruo-31
    すんません、オープンしてもらった罪滅ぼしに。
    @Dataが上書きされる恐れですが、
    ループの中でmy宣言しているので、ループ周回ごとに新しい配列が@Dataに割り当てられます。

    試しにコードを書いてみられては?

    >|
    use strict;
    use warnings;

    my @array;

    foreach my $a ( 0 .. 9 ) {
    my @Data=(($a*10)..(($a+1)*10-1));
    $array[$a]=\@Data;
    }

    map { print join(",",@{$_})."\n"; } @array;

    |<

    結果
    >|
    sh-3.1$ perl test3.pl
    0,1,2,3,4,5,6,7,8,9
    10,11,12,13,14,15,16,17,18,19
    20,21,22,23,24,25,26,27,28,29
    30,31,32,33,34,35,36,37,38,39
    40,41,42,43,44,45,46,47,48,49
    50,51,52,53,54,55,56,57,58,59
    60,61,62,63,64,65,66,67,68,69
    70,71,72,73,74,75,76,77,78,79
    80,81,82,83,84,85,86,87,88,89
    90,91,92,93,94,95,96,97,98,99
    sh-3.1$

    |<
  • id:uta_at_home
    質問者です。

    haruo-31さん、iu43lkjds32さん、コメント欄でも丁寧な回答を頂き、ありがとうございます。
    そういうことだったんですね。
    恥ずかしながら、my宣言で局所化することの意味を、みなさんの回答で初めて知りました。
    (今までは単にサブルーチンの中でだけ通用する変数か否かだけ定義しているものと思ってました)

    おかげで私の疑問は氷解し、すっきりしたプログラムが書けそうです。
    ありがとうございます。


    > なんか書き方からして、学校の授業ですか?

    いえ、私は学生時代が遠い昔になってしまったオヤジです。^^
    作業の効率化のため、最近 Perlを使い始めたのですが、独学なのでよく初歩的なところでつまづいてしまいます。
    自分で何日も悩んでいるよりも、はてなで質問したらすぐ解決してもらえることがわかって、みなさんに助けてもらうことがクセになっています。
    今回もたいへんお世話になりました。m(_"_)m
  • id:tkyk3
    し、しまった…間違って回答欄に書いてしまいました…。
    開く必要ありませんので…。
  • id:uta_at_home
    tkyk3さん
    いえいえ、もともと私がコメントではなく回答でお願いしますと書いていますので。

    みなさんのおかげで助かりました。
    ありがとうございました!
  • id:tkyk3
    コメント欄に書くつもりだったのに…。すみません。確認あるのにそれでも気づかないのって一体…と自分を笑ってしまいました。

    いるか、有り難うございます!

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません