给定一个,将一个数组切成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"]],
如何抽象出越来越多的嵌套循环以将其变成子slices(Int $p, Array @a)
?我想我需要某种高阶foreach
。
答案 0 :(得分:4)
当您需要任意数量的嵌套循环时,需要Algorithm::Loop的NestedLoops
。
use Algorithm::Loops qw( NestedLoops );
sub list_segments {
my ($array, $p) = @_;
my $iter = NestedLoops([
[ 0 ],
( map { my $d = $_; sub { [ $_+1 .. @$array-($p-$d) ] } } 1 .. $p-1 ),
[ 0+@$array ],
]);
return sub {
my @split_points = $iter->()
or return ();
return [
map [ @$array[ $split_points[$_] .. $split_points[$_+1]-1 ] ],
0..$#split_points-1
];
};
}
可以使用以下方法对此进行测试:
use Data::Dump qw( dd );
my $iter = list_segments(['A'..'F'], 3);
while ( my $list_segments = $iter->() ) {
dd($list_segments);
}
输出:
[["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"]]
顺便说一句,测试解决方案的简单方法是将结果数与C(N-1,p-1)=(N-1)进行比较! /(N-p)! /(p-1)!因为您实际上是从N-1个可能的分裂点中选择p-1个分裂点。
答案 1 :(得分:3)
您可能需要递归解决方案?
对于 p = 1 slices
只会一起返回所有项目。对于 p > 1,它获取第一个 n 项,并将 p 的项加入-每1 <= n <项目数。
#!/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;
}
输出:
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"]], )
(可能需要进行一些调整。例如检查1 <= p <=项数。)