如何抽象多个嵌套循环?

dax*_*xim 6 perl functional-programming

给定,将数组切成p大小≥1的部分:

my @a = 'A'..'F';

# p = 1
my @p1 = [@a];
# ["A" .. "F"]

# p = 2
my @p2;
for my $x (0..@a-2) {
    push @p2, [
        [@a[0..$x]],
        [@a[$x+1..@a-1]],
    ];
}
# [["A"], ["B" .. "F"]],
# [["A", "B"], ["C" .. "F"]],
# [["A", "B", "C"], ["D", "E", "F"]],
# [["A" .. "D"], ["E", "F"]],
# [["A" .. "E"], ["F"]],


# p = 3
my @p3;
for my $x (0..@a-3) {
    for my $y ($x+1..@a-2) {
        push @p3, [
            [@a[0..$x]],
            [@a[$x+1..$y]],
            [@a[$y+1..@a-1]],
        ];
    }
}
# [["A"], ["B"], ["C" .. "F"]],
# [["A"], ["B", "C"], ["D", "E", "F"]],
# [["A"], ["B", "C", "D"], ["E", "F"]],
# [["A"], ["B" .. "E"], ["F"]],
# [["A", "B"], ["C"], ["D", "E", "F"]],
# [["A", "B"], ["C", "D"], ["E", "F"]],
# [["A", "B"], ["C", "D", "E"], ["F"]],
# [["A", "B", "C"], ["D"], ["E", "F"]],
# [["A", "B", "C"], ["D", "E"], ["F"]],
# [["A" .. "D"], ["E"], ["F"]],


# p = 4
my @p4;
for my $x (0..@a-4) {
    for my $y ($x+1..@a-3) {
        for my $z ($y+1..@a-2) {
            push @p4, [
                [@a[0..$x]],
                [@a[$x+1..$y]],
                [@a[$y+1..$z]],
                [@a[$z+1..@a-1]],
            ];
        }
    }
}
# [["A"], ["B"], ["C"], ["D", "E", "F"]],
# [["A"], ["B"], ["C", "D"], ["E", "F"]],
# [["A"], ["B"], ["C", "D", "E"], ["F"]],
# [["A"], ["B", "C"], ["D"], ["E", "F"]],
# [["A"], ["B", "C"], ["D", "E"], ["F"]],
# [["A"], ["B", "C", "D"], ["E"], ["F"]],
# [["A", "B"], ["C"], ["D"], ["E", "F"]],
# [["A", "B"], ["C"], ["D", "E"], ["F"]],
# [["A", "B"], ["C", "D"], ["E"], ["F"]],
# [["A", "B", "C"], ["D"], ["E"], ["F"]],
Run Code Online (Sandbox Code Playgroud)

如何抽出越来越多的嵌套循环将其转换为子slices(Int $p, Array @a)?我想我需要某种更高阶foreach.

sti*_*bit 3

您可能会寻找递归解决方案?

对于p = 1 slices,仅返回所有项目。对于p > 1,它获取前n个项目,并针对每个 1 <= n < 项目数连接p - 1的项目。

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump qw(dump);

my @a = 'A' .. 'F';

for (my $i = 1; $i <= 4; $i++) {
  warn("p = $i\n");
  dump(slices($i, @a));
};

sub slices
{
  my $p = shift();
  my @a = @_;

  my @ret;

  if ($p == 1) {
    push(@ret, [[@a]]);
  }
  else {
    for (my $i = 0; $i < $#a; $i++) {
      foreach (slices($p - 1, @a[($i + 1) .. $#a])) {
        push(@ret, [([@a[0 .. $i]], @{$_})]);
      }
      # or shorter:
      #push(@ret, map({[([@a[0 .. $i]], @{$_})]} slices($p - 1, @a[($i + 1) .. $#a])));
    }
  }

  return @ret;
}
Run Code Online (Sandbox Code Playgroud)

输出:

p = 1
[["A" .. "F"]]
p = 2
(
  [["A"], ["B" .. "F"]],
  [["A", "B"], ["C" .. "F"]],
  [["A", "B", "C"], ["D", "E", "F"]],
  [["A" .. "D"], ["E", "F"]],
  [["A" .. "E"], ["F"]],
)
p = 3
(
  [["A"], ["B"], ["C" .. "F"]],
  [["A"], ["B", "C"], ["D", "E", "F"]],
  [["A"], ["B", "C", "D"], ["E", "F"]],
  [["A"], ["B" .. "E"], ["F"]],
  [["A", "B"], ["C"], ["D", "E", "F"]],
  [["A", "B"], ["C", "D"], ["E", "F"]],
  [["A", "B"], ["C", "D", "E"], ["F"]],
  [["A", "B", "C"], ["D"], ["E", "F"]],
  [["A", "B", "C"], ["D", "E"], ["F"]],
  [["A" .. "D"], ["E"], ["F"]],
)
p = 4
(
  [["A"], ["B"], ["C"], ["D", "E", "F"]],
  [["A"], ["B"], ["C", "D"], ["E", "F"]],
  [["A"], ["B"], ["C", "D", "E"], ["F"]],
  [["A"], ["B", "C"], ["D"], ["E", "F"]],
  [["A"], ["B", "C"], ["D", "E"], ["F"]],
  [["A"], ["B", "C", "D"], ["E"], ["F"]],
  [["A", "B"], ["C"], ["D"], ["E", "F"]],
  [["A", "B"], ["C"], ["D", "E"], ["F"]],
  [["A", "B"], ["C", "D"], ["E"], ["F"]],
  [["A", "B", "C"], ["D"], ["E"], ["F"]],
)
Run Code Online (Sandbox Code Playgroud)

(可能需要一些调整。比如检查 1 <= p <= 项目数。)