Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Perl中,如何迭代多个集合的笛卡尔积?_Perl_Algorithm_Cartesian Product - Fatal编程技术网

在Perl中,如何迭代多个集合的笛卡尔积?

在Perl中,如何迭代多个集合的笛卡尔积?,perl,algorithm,cartesian-product,Perl,Algorithm,Cartesian Product,给定x个数组,每个数组的元素数量可能不同,如何迭代所有组合,从每个数组中选择一个项目 例如: [ ] [ ] [ ] foo cat 1 bar dog 2 baz 3 4 sub cartesian { my @C = map { [ $_ ] } @{ shift @_ }; foreach (@_) { my @A = @$_;

给定x个数组,每个数组的元素数量可能不同,如何迭代所有组合,从每个数组中选择一个项目

例如:

[   ]   [   ]   [   ]
 foo     cat      1
 bar     dog      2
 baz              3
                  4
sub cartesian {
    my @C = map { [ $_ ] } @{ shift @_ };

    foreach (@_) {
        my @A = @$_;

        @C = map { my $n = $_; map { [ $n, @$_ ] } @C } @A;
    }

    return @C;
}
返回

[foo]   [cat]   [ 1 ]
[foo]   [cat]   [ 2 ]
  ...
[baz]   [dog]   [ 4 ]

顺便说一句,我是用Perl实现的。

一个针对任意数量列表的简单递归解决方案:

sub permute {
  my ($first_list, @remain) = @_;

  unless (defined($first_list)) {
    return []; # only possibility is the null set
  }

  my @accum;
  for my $elem (@$first_list) {
    push @accum, (map { [$elem, @$_] } permute(@remain));
  }

  return @accum;
}
sub make_generator {
  my @lists = reverse @_;

  my @state = map { 0 } @lists;

  return sub {
    my $i = 0;

    return undef unless defined $state[0];

    while ($i < @lists) {
      $state[$i]++;
      last if $state[$i] < scalar @{$lists[$i]};
      $state[$i] = 0;
      $i++;
    }

    if ($i >= @state) {
      ## Sabotage things so we don't produce any more values
      $state[0] = undef;
      return undef;
    }

    my @out;
    for (0..$#state) {
      push @out, $lists[$_][$state[$_]];
    }

    return [reverse @out];
  };
}

my $gen = make_generator([qw/foo bar baz/], [qw/cat dog/], [1..4]);
while ($_ = $gen->()) {
  print join(", ", @$_), "\n";
}
对于任意数量的列表,这不是一个简单的非递归解决方案:

sub permute {
  my ($first_list, @remain) = @_;

  unless (defined($first_list)) {
    return []; # only possibility is the null set
  }

  my @accum;
  for my $elem (@$first_list) {
    push @accum, (map { [$elem, @$_] } permute(@remain));
  }

  return @accum;
}
sub make_generator {
  my @lists = reverse @_;

  my @state = map { 0 } @lists;

  return sub {
    my $i = 0;

    return undef unless defined $state[0];

    while ($i < @lists) {
      $state[$i]++;
      last if $state[$i] < scalar @{$lists[$i]};
      $state[$i] = 0;
      $i++;
    }

    if ($i >= @state) {
      ## Sabotage things so we don't produce any more values
      $state[0] = undef;
      return undef;
    }

    my @out;
    for (0..$#state) {
      push @out, $lists[$_][$state[$_]];
    }

    return [reverse @out];
  };
}

my $gen = make_generator([qw/foo bar baz/], [qw/cat dog/], [1..4]);
while ($_ = $gen->()) {
  print join(", ", @$_), "\n";
}

我首先想到的一种方法是使用一对循环,而不是递归

查找置换的总数 从0到总置换-1的循环 请注意,通过将循环索引模数作为数组中元素的数量,可以得到每个排列 例如:

[   ]   [   ]   [   ]
 foo     cat      1
 bar     dog      2
 baz              3
                  4
sub cartesian {
    my @C = map { [ $_ ] } @{ shift @_ };

    foreach (@_) {
        my @A = @$_;

        @C = map { my $n = $_; map { [ $n, @$_ ] } @C } @A;
    }

    return @C;
}
给定A[3],B[2],C[3]

for (index = 0..totalpermutations) {
    print A[index % 3];
    print B[(index / 3) % 2];
    print C[(index / 6) % 3];
}
当然,可以将for循环替换为在[abc…]上循环,并且可以记忆一小部分。当然,递归更整洁,但这对于递归受到堆栈大小严重限制的语言可能很有用。

我的模块正是您想要的。请注意,您并不是真正在寻找置换,置换是一个集合中元素的顺序。您正在寻找叉积,它是来自不同集合的元素的组合

我的模块给你一个迭代器,所以你不需要在内存中创建它。只有在需要时才创建新的元组

use Set::Crossproduct;

my $iterator = Set::CrossProduct->new(
    [
        [qw( foo bar baz )],
        [qw( cat dog     )],
        [qw( 1 2 3 4     )],
    ]
    );

while( my $tuple = $iterator->get ) {
    say join ' ', $tuple->@*;
    }

关于笛卡尔乘积的递归和更流畅的Perl示例,以及注释和文档可以在

例如:

[   ]   [   ]   [   ]
 foo     cat      1
 bar     dog      2
 baz              3
                  4
sub cartesian {
    my @C = map { [ $_ ] } @{ shift @_ };

    foreach (@_) {
        my @A = @$_;

        @C = map { my $n = $_; map { [ $n, @$_ ] } @C } @A;
    }

    return @C;
}

可以使用嵌套循环

for my $e1 (qw( foo bar baz )) {
for my $e2 (qw( cat dog )) {
for my $e3 (qw( 1 2 3 4 )) {
   my @choice = ($e1, $e2, $e3); 
   ...
}}}
当需要任意数量的嵌套循环时,可以使用的NestedLoops


关于stackoverflow这个话题已经有很多了;只需搜索排列。我没有特别检查perl是否有。搜索置换是错误的,因为这不是一个置换。请注意,这里有一些不必要的分配,可以进一步优化。但这种通用方法正是您想要的:它并不是您真正想要的方法。在Perl中避免递归,不要在内存中创建整个过程。添加了非递归变量:permute有一个bug。每个内部列表的末尾都包含一个空数组引用。我认为它与三个嵌套循环相同,只是使用这种方法时,您还需要在过程中花费时间进行数学运算。只需做一点工作,这种方法就可以适用于任意数量的列表,而不是嵌套for循环。+1。。。当我试图重复这个模块的功能时,我没有看到你的帖子,我也不知道它的存在。