• ベストアンサー

配列から網羅的な文字列を生成するには?

perlの配列を使った、網羅的な文字列生成について質問です。 ある特定の種類の文字のレパートリをつかった、n文字の文字列すべての組み合わせを生成したいと考えています。 例えば文字 A, B, C の三種類をつかった2文字の文字列なら AA,AB,AC,BA,BB,BC,CA,CB,CC 3x3 =9 種類というふうになります。 n=2の場合、 @array = qw(A B C); foreach $moji(@array){ $moji1 = $moji; foreach $moji(@array){ $moji2 = $moji; $mojiretu = $moji1.$moji2; push (@mojiretuset , $mojiretu ); }} print @mojiretuset; とするとforeachをふたつ重ねることで文字の組み合わせすべてを生成できました。 問題なのは、問題なのは、今私がしたいのは文字数nを(ループの)外から指定して(例えば$mojisuu = 6 などとして)n文字の場合の網羅的な文字の組み合わせを生じさせることなのです。 毎回自分でforeachを必要なだけ重ねて書き直す、というのは現実的ではありませんし、n個のforeachの入ったperlのコードを書くコードというのも避けたいのです。 文字数を自由に後から設定して、特定の配列から網羅的な組み合わせを生じさせるにはどのようなコードを書けばよいでしょうか?

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

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

以下のコードでできると思います。 @resultに入っている文字列の末尾に1文字ずつ足しています。 (最初はforeachを使って書いたけど、途中でmap使った方がすっきりすると気づいた。) -------------------------------------------------- use strict; sub str_comb(\@$){   my @char_list = @{$_[0]}; #第1引数: 構成文字群   my $length = $_[1]; #第2引数: 文字列長   my @result = @char_list; #結果を格納する配列   for(my $i=1; $i<$length; $i++){     @result = map {       my $temp=$_;       map {$temp.$_} @char_list;     } @result;   }   return @result; } my @array = qw(A B C D); my @result = str_comb(@array,5); print join(",",@result); -------------------------------------------------- 別のやり方でも書いてみたのでそれも載せてみます。 人によってはこっちの方が分かりやすいと感じるかも? (あともしかしたら少し速いかも。) -------------------------------------------------- sub str_comb2(\@$){   my @char_list = @{$_[0]};   my $length = $_[1];   my $char_num = @char_list;   my @result = ();   for(my $i=0; ; $i++){     my $i_temp=$i;     my $str_temp="";     for(my $j=0; $j<$length; $j++){       $str_temp .= $char_list[$i_temp % $char_num];       $i_temp = int($i_temp / $char_num);     }     if($i_temp != 0){last;}     push(@result,$str_temp);   }   return @result; } --------------------------------------------------

hydrozoa
質問者

お礼

別の書き方を教えていただき、ありがとうございます。 人によって色々と違いが出てくるものですね。その辺、perlならではなのでしょうか。複数のコードを見比べることでより深く勉強できそうです。 有難うございました。

すると、全ての回答が全文表示されます。

その他の回答 (3)

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

> #3 > 最初の方法では, for は > for my $i (1 .. $length) > の方が綺麗ではないでしょうか>#2. たしかに、範囲演算子がある言語ではそっちの方がきれいですね。 C言語がメインなもので、しばらくperlさわってないと ついfor(;;)のスタイルで書いてしまいます。

すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

最初の方法では, for は for my $i (1 .. $length) の方が綺麗ではないでしょうか>#2.

すると、全ての回答が全文表示されます。
  • moon_piyo
  • ベストアンサー率60% (88/146)
回答No.1

こんちは ループをまわすたびに 現在の配列のすべての要素に、@arrayの内容をこつこつとくっつけてみました @array = qw(A B C); $n = 3; @mojiretuset = @array; foreach $i (2..$n) { @tmp = (); foreach $elm (@mojiretuset) { push(@tmp, (map $elm.$_, @array)); } @mojiretuset = @tmp; } print join ",", @mojiretuset;

hydrozoa
質問者

お礼

有難うございました。 コードを実行したところ、網羅的な文字列が出てきました。 foreach $i (2..$n) { や $temp を使うあたりが自分では考え付きませんでした。ループの制御というのは難しいですが、同時にとてもおもしろいものですね。

すると、全ての回答が全文表示されます。