我收到了一个谜题作为礼物,它由四个正方体组成,排成一排。每个立方体的面都是四种颜色之一。
为了解决这个谜题,必须将正方体定向,以使所有四个正方体的顶部不同,所有正方体的前面、后面和底部也不同。左侧和右侧不重要。
我的伪代码解决方案是:
1. 创建每个正方体的表示。 2. 获取每个正方体的所有可能的定向(每个正方体有24个)。 3. 获取每个正方体定向的所有可能组合。 4. 找到满足解决方案的定向组合。
我使用F#中该伪代码的实现解决了这个谜题,但对我完成第三步的方式不太满意。
为了解决这个谜题,必须将正方体定向,以使所有四个正方体的顶部不同,所有正方体的前面、后面和底部也不同。左侧和右侧不重要。
我的伪代码解决方案是:
1. 创建每个正方体的表示。 2. 获取每个正方体的所有可能的定向(每个正方体有24个)。 3. 获取每个正方体定向的所有可能组合。 4. 找到满足解决方案的定向组合。
我使用F#中该伪代码的实现解决了这个谜题,但对我完成第三步的方式不太满意。
let problemSpace =
seq { for c1 in cube1Orientations do
for c2 in cube2Orientations do
for c3 in cube3Orientations do
for c4 in cube4Orientations do
yield [c1; c2; c3; c4] }
上面的代码非常具体,仅计算了四个方向序列的笛卡尔积。我开始思考如何编写可以处理n个方向序列的代码。
我想到了以下代码(从现在开始的所有代码都应该可以在F#互动环境中正常执行):
// Used to just print the contents of a list.
let print =
Seq.fold (fun s i -> s + i.ToString()) "" >> printfn "%s"
// Computes the product of two sequences - kind of; the 2nd argument is weird.
let product (seq1:'a seq) (seq2:'a seq seq) =
seq { for item1 in seq1 do
for item2 in seq2 do
yield item1 |> Seq.singleton |> Seq.append item2 }
product 函数可以这样使用...
seq { yield Seq.empty }
|> product [ 'a'; 'b'; 'c' ]
|> product [ 'd'; 'e'; 'f' ]
|> product [ 'h'; 'i'; 'j' ]
|> Seq.iter print
...导致...
let productn (s:seq<#seq<'a>>) =
s |> Seq.fold (fun r s -> r |> product s) (seq { yield Seq.empty })
[ [ 'a'; 'b'; 'c' ]
[ 'd'; 'e'; 'f' ]
[ 'h'; 'i'; 'j' ] ]
|> productn
|> Seq.iter print
这正是我想要的用法。 productn 恰好具有我想要的签名,而且可行。
然而,使用 product 就需要那个讨厌的代码行 seq { yield Seq.empty },并且它(以不直观的方式)接受:
- 值序列 (seq<'a>)
- 值序列 的序列 (seq<seq<'a>>)
第二个参数看起来不正确。
那个奇怪的接口虽然被 productn 很好地隐藏了,但仍然会让我感到烦恼。
有没有更好、更直观的方法来通用地计算 n 个序列的笛卡尔积?是否有任何内置函数(或组合函数)可以做到这一点?
ss
,那么调用cart1 [for s in ss -> Seq.toList s]
即可。 - cferncart1 [for _ in 1..10 -> [1..1000]]
可以工作。当您有非常多(如10000)的输入序列时,该算法将导致堆栈溢出,因为它不是尾递归的。但是这样的输入似乎不太可能。 - cfern