プロが教えるわが家の防犯対策術!

複数の配列が定義されており、その各々から一つづつ要素を選んで出来る組み合わせの全てを表示したいのですが、その際に、foreachを単にネストするのではなく、より効率的方法や関数は何かありませんでしょうか。

たとえば、
@list_a = qw(1 2 3 4)
@list_b = qw(a b c d)
@list_c = qw(x y z)
の3つの配列の全て組み合わせ、例えば、
1ax 1ay 1az 1bx 1by 1bz 1cz ... 4dy 4dzを全て表示させるプログラムを作成したいと思っています。


foreach $a (@list_a){
foreach $b (@list_b){
foreach $c (@list_c){
...

のようにforeachをネストすればよいのですが、配列の数がとても多い場合を考えています。
宜しくお願い致します。

A 回答 (5件)

foreachは結局3つ使うけど、リストが増えても大丈夫そうではあった。


処理効率については特に考慮してません。

-------------------------------------------------------
my @list_a = qw(1 2 3 4);
my @list_b = qw(a b c d);
my @list_c = qw(x y z);
my @list_d = qw(+ - * /);
my @list_all = (\@list_a, \@list_b, \@list_c, \@list_d);

my @result = combination(@list_all);
print join(" ", @result);

sub combination(@){
  my @result = @{shift @_};
  foreach my $list (@_){
    my @temp = ();
    foreach my $item_x (@result){
      foreach my $item_y (@$list){
        push(@temp, $item_x . $item_y);
      }
    }
    @result = @temp;
  }
  return @result;
}
    • good
    • 0
この回答へのお礼

有難うございます。
多次元配列に不慣れで色々調べて、:-(理解できました。
まず@list_aと@list_bの組み合わせを作成し、次に、更にその組み合わせと@list_cの組み合わせを作成し。。。ということを@list_allでループしているのですね。
とても分かりやすかったです。
ところで、多次元配列でもう少し整理する必要があり、それは別の質問をなげようと思いますので、もし良ければそちらも宜しくお願い致します。

お礼日時:2007/02/24 20:04

頭の体操として考えてみました。


再起呼び出しとシンボリックリファレンスを利用した例です。
動かしてみたので自信はあります。
#&combineの最初の呼び出しの最初の引数は空文字列(シングルクォート二つ)です。

================================
#!/usr/bin/perl

$numVars = 3;
@var_1 = qw(1 2 3 4);
@var_2 = qw(a b c d);
@var_3 = qw(x y z);
for ($idx = 0; $idx <= $#var_1; $idx++) {
&combine('', 1, $idx);
}

sub combine {
my $outstr = $_[0];
my $depth = $_[1];
my $pos = $_[2];
my $idx = 0;
if ($depth <= $numVars) {
$outstr = $outstr . ${'var_' . $depth}[$pos];
if ($depth < $numVars) {
$depth++;
for ($idx = 0; $idx <= $#{'var_' . $depth}; $idx++) {
&combine($outstr, $depth, $idx);
}
} else {
print "$outstr\n";
return;
}
} else {
return;
}
}
    • good
    • 0

>実際には配列自体の数は10個~20個程度です。


この程度であれば、何とかなりそうです。
考え方としては、
foreach $elm_1 ($list_1){
foreach $elm_2 ($list_2){
foreach $elm_3 ($list_3){
foreach $elm_n ($list_n){
・・・
}}}
のソースを動的に作成し、それを実際に実行します。(evalを呼び出します)
以下のソースを実行して下さい。
------------------------------
#! /usr/bin/perl
# 以下の10個の配列にデータがある。
@list_1 = qw { t01-1 t01-2 t01-3 };
@list_2 = qw { t02-1 t02-2 t02-3 };
@list_3 = qw { t03-1 t03-2 t03-3 };
@list_4 = qw { t04-1 t04-2 t04-3 };
@list_5 = qw { t05-1 t05-2 t05-3 };
@list_6 = qw { t06-1 t06-2 t06-3 };
@list_7 = qw { t07-1 t07-2 t07-3 };
@list_8 = qw { t08-1 t08-2 t08-3 };
@list_9 = qw { t09-1 t09-2 t09-3 };
@list_10 = qw { t10-1 t10-2 t10-3 };
$max_tbl = 3;
for ($i = 1; $i <= $max_tbl; $i++){
$str .= " foreach \$elm_${i} (\@list_${i}) { \n ";
}
$str .= "\$yoso = \"\";";
for ($i = 1; $i <= $max_tbl; $i++){
$str .= "\$yoso .= \$elm_${i};";
$str .= "\$yoso .= ':';";
}

$str .= "print \$yoso;";
$str .= "print \"\\n\";";
$str .= "\n";
for ($i = 1; $i <= $max_tbl; $i++){
$str .= "}";
}

#print $str,"\n";
eval($str);
------------------------------
eval($str);をコメントアウトして、
#print $str,"\n";のコメントをはずすと、
動的に作成されたスクリプトの内容(=evalで実行される内容)が表示されます。
この場合、$max_tbl = 3;としていますが、ここに、テーブルの数を設定して下さい。
    • good
    • 0
この回答へのお礼

有難うございます。
foreach のループを自動生成させる、という考え方ですね。
直感的で直ぐ使える方法だと思いました。
eval関数を使ったことがなかったのですが、とても参考になりました。

お礼日時:2007/02/24 20:06

単に配列のインデックスをインクリメントするものです。



use strict;
my @a = qw(1 2 3 4); my $a_offset = 0; my $a_limit = $#a;
my @b = qw(a b c d); my $b_offset = 0; my $b_limit = $#b;
my @c = qw(x y z); my $c_offset = 0; my $c_limit = $#c;

while ($a_offset <= $a_limit) {
print "$a[$a_offset]$b[$b_offset]$c[$c_offset] ";
if ($c_offset < $c_limit) {
++$c_offset;
} elsif ($b_offset < $b_limit) {
$c_offset = 0;
++$b_offset;
} else {
$c_offset = $b_offset = 0;
++$a_offset;
}
}

print "\n";
    • good
    • 0
この回答へのお礼

拝見いたしました。
この方法では各配列の要素数を個別にインクリメントしているので、配列数が沢山あるとその分だけ、インクリメントの制御記述も沢山あることになり、結局はforeachを配列の個数分ネストするのと同じ冗長さがあるような気がしてしまいました。。。
しかし、多少はすっきりするので、こういう手もあるのかと気づきが得られました。
有難うございました。

お礼日時:2007/02/24 17:54

>配列の数がとても多い場合


とは、@list_a,@list_b,・・・・と、この配列自体の数がすごく多いと言うことでしょうか。
それとも、3つの配列のなかの、要素の数が、すごく多いのでしょうか。
また、実際問題として、具体的には、どのくらいまでなら、良いのでしょうか。配列自体の数が100万とか1000万とかありますか。
それとも、たかだか1000個以内、程度で良いのでしょうか。

この回答への補足

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

> とは、@list_a,@list_b,・・・・と、この配列自体の数がすごく多いと言うことでしょうか。
はい、@list_xの数自体が多いという意味です。要素の数ではありません。

実際には配列自体の数は10個~20個程度です。

以上ですが、いかがでしょうか。

補足日時:2007/02/24 14:39
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!