首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Perl:使用Algorithm::循环

Perl:使用Algorithm::循环
EN

Stack Overflow用户
提问于 2012-04-06 09:46:08
回答 2查看 638关注 0票数 4

我正在尝试使用NestedLoops函数在Perl语言中构造一个置换程序。下面是我的代码:

代码语言:javascript
复制
use strict;
use warnings;
use Algorithm::Loops qw(NestedLoops);

my @a = 'a'..'o';

my $length = 5;
my $start = 0;
my $depth = 2;

NestedLoops([
  [0..$length],
  ( sub {
    $start = 0 if $start == $depth;
    $start++;
    [$start * $length..$start * $length + $length - 1]
  }) x $depth,
], \&permute,);

sub permute {
  my @ind = @_;
  foreach my $i (@ind) {
    print $a[$i];
  }
  print "\n";
}

所以我有一个数组,里面有字母'a‘到'o’(大小是15)。我把数组当作有3行,所以我对数组的想象是这样的:

代码语言:javascript
复制
abcde
fghij
klmno

然后每个循环对应于每一行...我想要构建这样的排列:

代码语言:javascript
复制
afk
afl
afm
afn
afo
agk  // fails here... I end up getting agg
...

它适用于前5个值(最低的for循环的整个运行),但是第二次运行失败,因为最后一行的$start的值被重置为0……这是一个问题,因为它破坏了一切。

所以我想知道的是,我如何才能基于级别保持$start的值持久...所以我所要求的,本质上就是常量。我的循环应该看起来像这样:

代码语言:javascript
复制
for my $a (0..5) {        # 0 at this level and never change
  for my $b (5..10) {     # $start should be 5 at this level and never change
    for my $c (10..15) {  # $start should be 10 at this level and never change
      permute($a, $b, $c);
    }
  }
}

现在,因为我将有一个可变长度的for循环,我不能硬编码每个起始值,所以我正在寻找一种方法来最初创建那些起始值,然后将它们保留下来,以便在循环重置时使用。

我意识到这是一个令人困惑的问题,所以请提出问题,我将帮助澄清。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-04-06 14:36:50

你让这件事变得更难了。

部分问题是NestedLoops的文档没有详细说明如何使用第一个参数中的子例程引用。

对于下面的示例,假设这是在它们上面的某个地方编写的。

代码语言:javascript
复制
use strict;
use warnings;
use Algorithm::Loops qw'NestedLoops';

实际上,调用NestedLoops以获得所需内容的最简单方法如下:

代码语言:javascript
复制
NestedLoops(
  [
    ['a'..'e'],
    ['f'..'j'],
    ['k'..'o'],
  ],
  \&permute
);

sub permute {
  print @_, "\n";
}

如果您真的希望动态生成NestedLoops的参数,我建议您使用List::MoreUtils中的part

代码语言:javascript
复制
use List::MoreUtils qw'part';

my @a = 'a'..'o';

my $length = 5;
my $index;

NestedLoops(
  [
    part {
      $index++ / $length
    } @a
  ],
  \&permute
);

sub permute {
  print @_, "\n";
}

如果出于某种原因,您希望在数组中调用带有索引的NestedLoops,使用part仍然很容易。

代码语言:javascript
复制
use List::MoreUtils qw'part';

my @a = 'a'..'o';

my $length = 5;

NestedLoops(
  [
    part {
      $_ / $length
    } 0..@a-1
  ],
  \&permute
);

sub permute {
  print map { $a[$_] } @_;
  print "\n";
}

实际上,您遇到的主要问题是,您提供给NestedLoops的两个子例程引用修改了相同的变量,并且它们都被多次调用。解决这个问题的最好方法是依赖于子例程被调用时的最后一个值。(从实现上看,这似乎更接近于它的使用方式。)

代码语言:javascript
复制
my @a = 'a'..'o';

my $length = 5;
my $depth = 3;

NestedLoops(
  [
    [0..$length-1],
    (sub{
      return  unless @_;
      my $last = pop;
      my $part = int( $last / $length ) + 1; # current partition
      my $start = $part * $length; # start of this partition
      my $end = $start + $length;
      [$start..$end-1] # list of variables in this partition
    }) x ($depth-1)
  ],
  \&permute
);

sub permute {
  print map { $a[$_] } @_;
  print "\n";
}
票数 4
EN

Stack Overflow用户

发布于 2012-04-06 19:10:53

使用子例程生成循环范围时,每次必须启动其中一个嵌套循环时都会调用该子例程。这意味着对包含循环的每次迭代都执行一次。在每次调用之前,$_被设置为包含循环的变量的当前值,并且所有包含循环变量的值都作为参数传递。

为了阐明这一点,您编写的NestedLoops语句等同于

代码语言:javascript
复制
sub loop_over {
  $start = 0 if $start == $depth;
  $start++;
  [$start * $length..$start * $length + $length - 1]
};

NestedLoops([
  [0..$length],
  (\&loop_over) x $depth,
], \&permute,);

在原始的Perl中,它看起来类似于

代码语言:javascript
复制
for my $i (0 .. $length) {

  $_ = $i;
  my $list = loop_over($i);

  for my $j (@$list) {

    $_ = $j;
    my $list = loop_over($i, $j);

    for my $k (@$list) {
      permute($i, $j, $k);
    }
  }
}

因此,也许现在更清楚的是,您对$start的计算是错误的?在执行上升以重新启动包含循环之前,会对最里面的级别重新计算几次。

由于传递给子例程的参数由包含循环变量的所有值组成,因此可以检查@_的大小,以了解要为哪个级别的循环生成一个范围。例如,在上面的代码中,如果@_包含两个值,分别是$i$j,则必须返回$k的值;或者,如果只有一个参数,则它是$i的值,返回值必须是$j的范围。因此,您的$start的正确值就是@_中的元素数量,可以使用my $start = @_;进行设置。

使用此方法,子例程也可以返回最外层循环的范围。代码如下所示

代码语言:javascript
复制
use strict;
use warnings;

use Algorithm::Loops qw(NestedLoops);

my @a = 'a'..'o';

my $length = 5;
my $start = 0;
my $depth = 2;

NestedLoops([
  (sub {
    $start = @_;
    [$start * $length .. $start * $length + $length - 1];
  }) x ($depth + 1)
], \&permute,);

sub permute {
  print map { $a[$_] } @_;
  print "\n";
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10038251

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档