我在Perl数组中有一个数学集:(1,2,3)。我想找到那一组的所有子集:(1),(2),(3),(1,2),(1,3),(2,3)。
使用3个元素这不是太难,但如果设置有10个元素,这会变得棘手。
思想?
答案 0 :(得分:12)
您可以像Matthew提到的那样使用 Data::PowerSet 。但是,如果如您的示例中所示,您只需要适当的子集而不是每个子集,那么您需要做更多的工作。
# result: all subsets, except {68, 22, 43}.
my $values = Data::PowerSet->new({max => 2}, 68, 22, 43);
同样,如果要省略空集,只需添加min
参数:
# result: all subsets, except {} and {68, 22, 43}.
my $values = Data::PowerSet->new({min => 1, max => 2}, 68, 22, 43);
否则,要获取所有子集,只需省略两个参数:
# result: every subset.
my $values = Data::PowerSet->new(68, 22, 43);
答案 1 :(得分:4)
答案 2 :(得分:3)
既然你说“数学集”,我认为你的意思是没有重复。
一个适用于多达32个元素的简单实现:
my $set = [1,2,3];
my @subsets;
for my $count ( 1..(1<<@$set)-2 ) {
push @subsets, [ map $count & (1<<$_) ? $set->[$_] : (), 0..$#$set ];
}
(对于整个范围的子集,循环从0到(1&lt;&lt;&lt; @ $ set)-1;排除0排除空集,排除(1&lt;&lt;&lt; @ $ set)-1排除原始集。)
更新:我并不是主张使用模块,只是在你想要了解如何解决这个问题时提出建议。通常,每个元素都包含在任何给定子集中或从中排除。您想要选择一个元素并首先生成其他元素的所有可能子集,不包括您选择的元素,然后生成其他元素的所有可能子集,包括您选择的元素。递归地将其应用于“生成所有可能的子集”。最后,丢弃空子集和非正确子集。在上面的代码中,每个元素都分配了一个位。首先是所有子集 高位开启,然后所有关闭它的人。对于这些替代方案中的每一个,首先生成子集,然后关闭下一个最高位,然后打开。继续这个直到你只是在最低位工作,你最终得到的是所有可能的数字,按顺序。
答案 3 :(得分:1)
答案 4 :(得分:1)
如果您不想使用现有模块或不能使用现有模块,则只需使用bit-mask and a binary counter编写自己的子集生成算法。示例代码如下 -
#!/usr/bin/perl
use strict;
use warnings;
my @set = (1, 2, 3);
my @bitMask = (0, 0, 0); #Same size as @set, initially filled with zeroes
printSubset(\@bitMask, \@set) while ( genMask(\@bitMask, \@set) );
sub printSubset {
my ($bitMask, $set) = @_;
for (0 .. @$bitMask-1) {
print "$set->[$_]" if $bitMask->[$_] == 1;
}
print"\n";
}
sub genMask {
my ($bitMask, $set) = @_;
my $i;
for ($i = 0; $i < @$set && $bitMask->[$i]; $i++) {
$bitMask->[$i] = 0;
}
if ($i < @$set) {
$bitMask->[$i] = 1;
return 1;
}
return 0;
}
注意:我无法测试代码,可能需要解决一些错误。
答案 5 :(得分:1)
这是一个计数问题 - 对于N个元素,确实有2 ^ N个子集,你必须从0到2 ^ N - 1计算二进制数,以便全部列出。
对于例如3个项目,有8个可能的子集:000,001,010,011,100,101,110和111 - 数字显示哪些成员存在。