• ベストアンサー

複数の配列の全ての組み合わせを表示する方法

複数の配列が定義されており、その各々から一つづつ要素を選んで出来る組み合わせの全てを表示したいのですが、その際に、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をネストすればよいのですが、配列の数がとても多い場合を考えています。 宜しくお願い致します。

  • Perl
  • 回答数5
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
  • Werner
  • ベストアンサー率53% (395/735)
回答No.1

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; }

tk_1980024
質問者

お礼

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

その他の回答 (4)

  • aton
  • ベストアンサー率47% (160/334)
回答No.5

頭の体操として考えてみました。 再起呼び出しとシンボリックリファレンスを利用した例です。 動かしてみたので自信はあります。 #&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; } }

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.4

>実際には配列自体の数は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;としていますが、ここに、テーブルの数を設定して下さい。

tk_1980024
質問者

お礼

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

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.3

単に配列のインデックスをインクリメントするものです。 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";

tk_1980024
質問者

お礼

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

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

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

tk_1980024
質問者

補足

回答ありがとうございます。補足です。 > とは、@list_a,@list_b,・・・・と、この配列自体の数がすごく多いと言うことでしょうか。 はい、@list_xの数自体が多いという意味です。要素の数ではありません。 実際には配列自体の数は10個~20個程度です。 以上ですが、いかがでしょうか。

関連するQ&A

  • 行列 連立一次方程式

    a,b,c,d,が0でない実数であるとき、次の連立一次方程式を解け ax-by-az+bu=1 bx+ay-bz-au=0 cx-dy+cz-du=0 dx+cy+dz+cu=0 行列を使った解き方でお願いします。

  • 多項式代数計算のソフトを教えて!

    或る数学の論文を書くために代数計算をやっています.以下のA, B, C, D から (B/A)=(D/C) となるかどうかを確かめる計算ソフトを教えて下さい.現在,手持ちの計算ソフトは「カルキング Ver.5」のみで,これでは計算不能です. B=(a+b+cx+dy)dz+{a+(c+d)z}{ax+by+(c+d)xy} A=(a+b+dz)(a+b+cx+dy)+c{ax+by+(c+d)xy} D=a(a+b+cy+dz){ax+bz+(c+d)xz}+b(a+b+cx+dz){ay+bz+(c+d)yz} +(c+d){ax+bz+(c+d)xz}{ay+bz+(c+d)yz} C=(a+b)(a+b+cx+dz)(a+b+cy+dz)+c(a+b+cy+dz){ax+bz+(c+d)xz} +d(a+b+cx+dz){ay+bz+(c+d)yz} これらは(B/A)=(D/C)とはならないでしょうか?(dy, dz は微分の意味ではありません)また,数値計算ではなく数式処理(代数計算)のソフトは何がいいでしょうか? 微分,積分,特殊関数(楕円関数など)よりも10次以上の正方行列や行列式,50項以上の多項式の乗法計算や因数分解が楽に早くできるソフトは何がいいでしょうか?おこころあたりの方,教えて下さい.

  • 因数分解で悩んでいます

    因数分解の発展問題でつまずいています。 (1) (ax+by+cz)^2+(bx-ay)^2+(cy-bz)^2+(az-cx)^2 (2) (x-b)(x-c)(b-c)+(x-c)(x-a)(c-a)+(x-a)(x-b)(a-b) です。どちらの問題も、同じような文字がたくさんあるので 、[x]などに注目したりして因数分解しようとしましたが、上手く出来ません。 教えて下さい。

  • 行列式の値の計算

    行列式の値の計算が、あっているか確かめたいのですが。 対象式は、以下のとおりです。   | ax - dx  ay - dy  az - dz |   | bx - dx  by - dy  bz - dz |   | cx - dx  cy - dy  cz - dz |  =  axbycz - axbydz + axcydz - axcybz + axdybz - axdycz    - bxaycz + bxaydz - bxcydz + bxcyaz - bxdyaz + bxdycz    + cxaybz - cxaydz + cxbydz - cxbyaz + cxdyaz - cxdybz    - dxaybz + dxaycz - dxbycz + dxbyaz - dxcyaz + dxcybz 代数演算ソフト等を持っておられる方は、前式が成り立っているかどうかを 確認していただけませんでしょうか。 間違っている場合は、正しい展開式を示していただければ幸いです。 よろしくお願いします。

  • 周波数特性の問題

    以下の問題について、解答をできるだけわかりやすく教えていただけないでしょうか。 H(z)= (c+bz^-1+az^-2)/(a+bz^-1+cz^-2)の振幅特性がA(ω)=|H(e^jw)|=1であることを示しなさい。 a,b,cは実数 宜しくお願いします。

  • 連想配列の一部分を全て表示したいのですが・・。

    すみません。phpの事はあまりわからないのですが、以下のような連想配列がありまして、 (下記のような連想配列が大量にあります。) Array ( [0] => Array ( [a] => 1111 [0] => 1111 [b] => 2222 [1] => 2222 [c] => 3333 [2] => 3333 ) [1] => Array ( [a] => 5555 [0] => 5555 [b] => 6666 [1] => 6666 [c] => 7777 [2] => 7777 ) ) 上の配列から下記の配列のみ全て表示したいのですがどう記述したらよいでしょうか。 Array[0][a] Array[0][b] Array[0][c] Array[1][a] Array[1][b] Array[1][c]

    • ベストアンサー
    • PHP
  • ベクトルの解析について

    ベクトルA、Bに対して div(A×B)=BrotA-ArotBを示せという問題で、 div(A×B)=det[(∂/∂x, ∂/∂y, ∂/∂z), (Ax, Ay, Az), (Bx, By, Bz)] BrotA=det[(Bx, By, Bz), (∂/∂x, ∂/∂y, ∂/∂z), (Ax, Ay, Az)] ArotB=det[(Ax, Ay, Az), (∂/∂x, ∂/∂y, ∂/∂z), (Bx, By, Bz)] というところまでは分かったのですが、サラスで展開してもイコールになりません。どうすればイコールになるんですか? どなたか教えていただけないでしょうか?

  • [perl]サブルーチンに渡す値が配列でもスカラーでも同様に処理できるようにしたい

    &test( [ X ] , [ Y ]); X:配列またはスカラー Y:スカラー のような形でサブルーチンに渡し、Xが配列であってもスカラーであっても新しい配列にpushしたいのですが、どうしてよいのか分かりません。 具体的には $a = 100; @b = qw/1 2 3 4 5/; $c = 500; のとき、 &test($a, $c);なら @array = qw/100/; $scalar = 500; &test(@b, $c);なら @array = qw/1 2 3 4 5/; $scalar = 500; のようにしたいのです。 なお、&test($a, @b, $c);のように引数を三つにして送る方法は仲間に却下されてしまいました。 なるべく引数は二つの方向でお願いいたします。

    • ベストアンサー
    • Perl
  • 複素積分について

    ∫[0→2π]dθ/(a+bcosθ)の値を求めよという計算です。 z=exp(iθ)とおくと、、 またcosθ=(1/2)(z+1/z)となるので、 この積分は、 2/i∫1/(bz^2+2az+b)dz となり、bz^2+2az+b=0の根が特異点となるので、 その根をα、βとおくと、 2/i∫1/(z-α)(z-β)dzとなったのですが、 答えを見ると、 2/ib∫1/(z-α)(z-β)dz となっています。 分母にbがあるのですが、このbはどっからきたのでしょうか?

  • 空間上の二点を結ぶ直線上に任意の点が存在するかどうかの関数

    Cの初心者です。 空間上に存在する2点間を結ぶ直線上に任意の点が存在するかどうかの 関数を作りたいのですがどのような公式を用いて評価すればいいのか分かりません。 どなたかご教示ください。 引数    始点 A(x,y,z)    終点 B(x,y,z)    直線上に存在するであろう任意の点       C(x,y,z)  関数のイメージ    boolean isOnLine (Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz); 配列でもよいです。 返り値    True、 False  ( 0 or 1 ) よろしくお願いします。

専門家に質問してみよう