由于我不太了解这些类型的算法的语言(即如何谷歌这个),我只是展示我正在寻找的东西:
我有三个数组(源数组的长度不相等):
$array1 = array('A', 'B', 'C', 'D');
$array2 = array('x', 'y', 'z');
$array3 = array('1', '2', '3');
我希望这些数组的所有可能组合在哪里:
ABC
总是在xyz
总是在123
之前出现。)结果将是:
array(
array('A', 'x', '1'),
array('A', 'x', '2'),
array('A', 'x', '3'),
array('A', 'y', '1'),
// etc ...
// But I also need all the partial sets, as long as the rule about
// ordering isn't broken i.e.:
array('B'),
array('B', 'x'),
array('B', 'x', '1'),
array('x'),
array('x', '1'),
array('1'),
);
结果的顺序对我来说无关紧要。
在php中工作,但类似的语言或伪代码当然没问题。或者我只是简单介绍一下我应该关注的特定类型的排列/组合算法。
答案 0 :(得分:2)
我会说这些是笛卡尔积。生成它们非常容易。
对于固定数量的数组(在Perl中):
for my $a(@arrayA) {
for my $b(@arrayB) {
push @result, [$a, $b];
}
}
一般程序:假设@partial
是A1 x A2 x ... x An
的笛卡尔积的数组,我们想要A1 x ... x An x An+1
for my $a(@partial) {
for my $b(@An_plus_1) {
push @result, [@$a, $b];
}
}
这显然需要迭代所有数组。
现在,你想要省略集合中的一些元素,你只需稍微扭曲一下。在第一种方法中,您可以向每个数组添加另一个元素(undef
是明显的选择,但任何事情都可以),然后在结果集中过滤掉这些元素。在第二种方法中,它更容易:您只需将@partial
和map { [$_] } @An_plus_1
添加到结果中(或者,在英语中,由A1 x ... x An
的部分笛卡尔积所得的所有集合加上单个元素集由新集合的元素组成。)
答案 1 :(得分:0)
使用RBarryYoung的提示,这是生成它们的最短方式,bash(和sed,删除D,w和4):
echo {A..D}{w..z}{1..4} | sed 's/[Dw4]//g'
A1 A2 A3 A Ax1 Ax2 Ax3 Ax Ay1 Ay2 Ay3 Ay Az1 Az2 Az3 Az B1 B2 B3 B Bx1 Bx2 Bx3 Bx By1 By2 By3 By Bz1 Bz2 Bz3 Bz C1 C2 C3 C Cx1 Cx2 Cx3 Cx Cy1 Cy2 Cy3 Cy Cz1 Cz2 Cz3 Cz 1 2 3 x1 x2 x3 x y1 y2 y3 y z1 z2 z3 z
另一种简单的方法是SQL,它默认使用它:
SELECT upper, lower, num
FROM uppers, lowers, numbers
WHERE upper in ('A', 'B', 'C', ' ')
AND lower in (' ', 'x', 'y', 'z')
AND (number in (1, 2, 3) OR number IS NULL);
如果你的表只包含'A,B,C,'和'x,y,z,'和'1,2,3',那就更短了:
SELECT upper, lower, num
FROM uppers, lowers, numbers;
除了笛卡儿产品之外,这个组合的另一个词是跨产品。
对于未知数量的未知大小的Lists / Sequences /其他集合,我建议使用迭代器 - 如果PHP有这样的东西。这是Scala中的一个实现:
class CartesianIterator (val ll: Seq[Seq[_]]) extends Iterator [Seq[_]] {
var current = 0
def size = ll.map (_.size).product
lazy val last: Int = len
def get (n: Int, lili: Seq[Seq[_]]): List[_] = lili.length match {
case 0 => List ()
case _ => {
val inner = lili.head
inner (n % inner.size) :: get (n / inner.size, lili.tail)
}
}
override def hasNext () : Boolean = current != last
override def next (): Seq[_] = {
current += 1
get (current - 1, ll)
}
}
val ci = new CartesianIterator (List(List ('A', 'B', 'C', 'D', ' '), List ('x', 'y', 'z', ' '), List (1, 2, 3, 0)))
for (c <- ci) println (c)
List(A, x, 1)
List(B, x, 1)
List(C, x, 1)
List(D, x, 1)
List( , x, 1)
List(A, y, 1)
List(B, y, 1)
...
List( , z, 0)
List(A, , 0)
List(B, , 0)
List(C, , 0)
List(D, , 0)
List( , , 0)
可以使用包装器从输出中删除'0'和''。