我有一个名为cube的类型,它代表一个物理多维数据集。我编写了一些采用立方体的代码,并生成了多维数据集所有可能方向的列表。
我使用了以下术语,假设立方体在我眼前坐在我面前。
对于立方体的面孔:
对于轴,立方体可以旋转:
当6个面中的每一个面朝下时,立方体可以以不同的方式(0°,90°,180°和270°)围绕其法线轴旋转。这导致24种可能的方向。
我已经开始使用立方体类型(请原谅S / O的语法着色):
type 'a cube(top:'a, bottom:'a, left:'a, right:'a, front:'a, back:'a) =
member this.Top = top
member this.Bottom = bottom
member this.Left = left
member this.Right = right
member this.Front = front
member this.Back = back
override this.ToString() =
sprintf "Top: %O, Bottom: %O, Left: %O, Right: %O Front: %O, Back: %O" top bottom left right front back
然后我继续编写一个Cube模块,它提供了函数getOrientations。
module Cube =
let rotateNormalRight (c:'a cube) =
cube(c.Top, c.Bottom, c.Back, c.Front, c.Left, c.Right)
let rotateLongitudinalRight (c:'a cube) =
cube(c.Left, c.Right, c.Bottom, c.Top, c.Front, c.Back)
let rotateLongitudinalLeft (c:'a cube) =
cube(c.Right, c.Left, c.Top, c.Bottom, c.Front, c.Back)
let private operations =
[ rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalRight
rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalRight
rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalLeft
rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalLeft
rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalRight
rotateNormalRight; rotateNormalRight; rotateNormalRight ]
let getOrientations startCube =
let rec getCubeInner (ops:('a cube -> 'a cube) list) (cl:'a cube list) =
match ops with
| [] -> cl
| op :: rest -> getCubeInner rest ((cl |> List.hd |> op) :: cl)
getCubeInner operations [startCube]
这个模块只提供三种可能的90度旋转,一个旋转列表,每个可能的方向都有一个立方体,以及一个产生给定一个立方体的所有方向的函数。
如果我这样做:
cube(1, 2, 3, 4, 5, 6)
|> Cube.getOrientations
|> List.iter (printfn "%O")
我明白了:
Top: 3, Bottom: 4, Left: 1, Right: 2 Front: 6, Back: 5
Top: 3, Bottom: 4, Left: 6, Right: 5 Front: 2, Back: 1
Top: 3, Bottom: 4, Left: 2, Right: 1 Front: 5, Back: 6
Top: 3, Bottom: 4, Left: 5, Right: 6 Front: 1, Back: 2
Top: 6, Bottom: 5, Left: 3, Right: 4 Front: 1, Back: 2
Top: 6, Bottom: 5, Left: 1, Right: 2 Front: 4, Back: 3
Top: 6, Bottom: 5, Left: 4, Right: 3 Front: 2, Back: 1
Top: 6, Bottom: 5, Left: 2, Right: 1 Front: 3, Back: 4
Top: 2, Bottom: 1, Left: 5, Right: 6 Front: 3, Back: 4
Top: 2, Bottom: 1, Left: 3, Right: 4 Front: 6, Back: 5
Top: 2, Bottom: 1, Left: 6, Right: 5 Front: 4, Back: 3
Top: 2, Bottom: 1, Left: 4, Right: 3 Front: 5, Back: 6
Top: 4, Bottom: 3, Left: 1, Right: 2 Front: 5, Back: 6
Top: 4, Bottom: 3, Left: 5, Right: 6 Front: 2, Back: 1
Top: 4, Bottom: 3, Left: 2, Right: 1 Front: 6, Back: 5
Top: 4, Bottom: 3, Left: 6, Right: 5 Front: 1, Back: 2
Top: 5, Bottom: 6, Left: 4, Right: 3 Front: 1, Back: 2
Top: 5, Bottom: 6, Left: 1, Right: 2 Front: 3, Back: 4
Top: 5, Bottom: 6, Left: 3, Right: 4 Front: 2, Back: 1
Top: 5, Bottom: 6, Left: 2, Right: 1 Front: 4, Back: 3
Top: 1, Bottom: 2, Left: 5, Right: 6 Front: 4, Back: 3
Top: 1, Bottom: 2, Left: 4, Right: 3 Front: 6, Back: 5
Top: 1, Bottom: 2, Left: 6, Right: 5 Front: 3, Back: 4
Top: 1, Bottom: 2, Left: 3, Right: 4 Front: 5, Back: 6
这就是我想要的。但是Cube模块被大量的操作所占用。
是否有更好的方法可以通过更少的操作或完全不同的方法来实现这一目标?
答案 0 :(得分:2)
首先要考虑的是:如果你纵向旋转立方体,那么做其他操作,操作序列更加规则。 (它变成[长,正常,正常,正常]时间6)。你可以想象将它浓缩成4个操作的列表,特别是在一秒钟内。而且,在此列表的3次迭代之后,您最终得到了与之相同的多维数据集。
现在,考虑到你在旋转时看到的每个方向,也有一个“相反”的方向。 (IE:对于每个方向(U,D,L,R,F,B),都有相应的方向(D,U,L,R,B,F)。(想象一下你和外太空的朋友,每个上部 - 相对于另一个,以及你们每个人在立方体的两侧。)在前12次操作中的每一次([长 - 左,正常,正常,正常]时间3)之后,最终的三个方面你的“顶级”永远不会出现在“底层” - 也就是说,你看到的和你朋友看到的东西之间没有重叠。如果你的朋友也注意到了他看到的东西(如果你添加你的观点,请阅读你可以将转数减半。
所以(在伪代码中,因为我不知道F#):
ops = [rotateLongLeft, rotateNormalRight, rotateNormalRight, rotateNormalRight]
for each operation in [ops times 3]:
do the operation
add the orientation
add its opposite
最后,你应该拥有所有24个方向。
答案 1 :(得分:2)
这可能稍微清洁一点:
let rec expand = function
| [] -> []
| (0,o)::l -> expand l
| (n,o)::l -> o::(expand ((n-1,o)::l))
let getOrientations startCube =
expand [
3,rotateNormalRight; 1,rotateLongitudinalRight
3,rotateNormalRight; 1,rotateLongitudinalRight
3,rotateNormalRight; 1,rotateLongitudinalLeft
3,rotateNormalRight; 1,rotateLongitudinalLeft
3,rotateNormalRight; 1,rotateLongitudinalRight
3,rotateNormalRight]
|> List.scan (|>) startCube
expand
函数获取重复/元素对的列表,并将其扩展为元素列表,这使得操作列表看起来更清晰(至少对我来说)。然后,我们可以使用内置的List.scan
函数来遍历该列表,并将每个函数连续应用于上一个结果。