13

Perlで順列をやりたいです。たとえば、私は 3 つの配列を["big", "tiny", "small"]持ってい["red", "yellow", "green"]ます["apple", "pear", "banana"]

入手方法:

[「大きい」「赤い」「りんご」]
【「大」「赤」「梨」】

..等..

【「小」「緑」「バナナ」】

これは順列と呼ばれることを理解しています。しかし、私はそれを行う方法がわかりません。また、いくつの配列を使用できるかわかりません。3 つまたは 4 つある可能性があるため、ネストされたループは実行したくありません。

4

6 に答える 6

16

それは実際には順列ではなく、デカルト積です。Math::Cartesian::Productを参照してください。

#!/usr/bin/perl

use strict; use warnings;

use Math::Cartesian::Product;

cartesian { print "@_\n" }
    ["big", "tiny", "small"],
    ["red", "yellow", "green"],
    ["apple", "pear", "banana"];

出力:

C:\Temp> uu
大きな赤いリンゴ
大きな赤梨
大きな赤いバナナ
大きな黄色いリンゴ
大きな黄色い梨
大きな黄色いバナナ
大きな青リンゴ
大きな緑の梨
大きな緑のバナナ
小さな赤いリンゴ
小さな赤梨
小さな赤いバナナ
小さな黄色いリンゴ
小さな黄色い梨
小さな黄色いバナナ
小さな青リンゴ
小さな緑の梨
小さな緑のバナナ
小さい赤いりんご
小さな赤梨
小さな赤いバナナ
小さな黄色いリンゴ
小さな黄色い梨
小さな黄色いバナナ
小さな青リンゴ
小さな緑の梨
小さな緑のバナナ
于 2010-03-16T18:40:04.913 に答える
8

今ツイッター形式で:

sub prod { reduce { [ map { my $i = $_; map [ @$_, $i ], @$a } @$b ] } [[]], @_ }

use strict;
use warnings;
use List::Util qw(reduce);

sub cartesian_product {
  reduce {
    [ map {
      my $item = $_;
      map [ @$_, $item ], @$a
    } @$b ]
  } [[]], @_
}
于 2010-03-16T20:37:20.440 に答える
6

私は数年前にこの正確な問題を解決しなければなりませんでした。私は自分の解決策を思いつくことができませんでしたが、代わりmapに、再帰とともに巧妙かつ賢明に使用する次の素晴らしいコードに出くわしました。

#!/usr/bin/perl

print "permute:\n";
print "[", join(", ", @$_), "]\n" for permute([1,2,3], [4,5,6], [7,8,9]);

sub permute {

    my $last = pop @_;

    unless(@_) {
           return map([$_], @$last);
    }

    return map { 
                 my $left = $_; 
                 map([@$left, $_], @$last)
               } 
               permute(@_);
}

はい、これはクレイジーに見えますが、説明させてください! 関数@_は空になるまで再帰し、その時点で([1], [2], [3])(3 つの arrayref のリスト) を前のレベルの再帰に戻します。そのレベル$lastには、 を含む配列への参照があります[4, 5, 6]

$_外側のマップの本体は、 set to [1]、次に[2]、最後にで 3 回実行され[3]ます。(4, 5, 6)次に、外側のマップの反復ごとに内側のマップが実行され([1, 4], [1, 5], [1, 6])、 、([2, 4], [2, 5], [2, 6])、および最後にが返されます([3, 4], [3, 5], [3, 6])

最後から 2 番目の再帰呼び出しは を返します([1, 4], [1, 5], [1, 6], [2, 4], [2, 5], [2, 6], [3, 4], [3, 5], [3, 6])

次に、その結​​果を に対して実行し[7,8,9]ます。[1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 5, 7], [1, 5, 8], [1, 5, 9], [1, 6, 7], [1, 6, 8], [1, 6, 9], [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 5, 7], [2, 5, 8], [2, 5, 9], [2, 6, 7], [2, 6, 8], [2, 6, 9], [3, 4, 7], [3, 4, 8], [3, 4, 9], [3, 5, 7], [3, 5, 8], [3, 5, 9], [3, 6, 7], [3, 6, 8], [3, 6, 9]

perlmonks.org に質問を投稿して、誰かに説明してもらったことを覚えています。

このソリューションを問題に簡単に適応させることができます。

于 2010-03-16T18:38:55.540 に答える
6

必要に応じて、私のSet::CrossProductモジュールを使用できます。イテレータが提供されるため、スペース全体をトラバースする必要がないため、制御できます。

于 2010-03-16T21:11:14.747 に答える
1

もしも

  • 依存関係を含めたくない
  • 配列の数が少ない
  • あなたの配列は本当に巨大ではありません

次に、これを簡単に行うことができます:

2 つの配列@xsと の場合@ys:

map{ my $x = $_; map { [$x, $_] } @ys } @xs

3 つの配列@xs@ys@zs

map{ my $x = $_; map { my $y = $_; map { [$x, $y, $_] } @zs } @ys } @xs
于 2015-10-29T17:15:46.460 に答える