获取所有可能的邻居坐标

时间:2020-12-20 19:24:18

标签: haskell functional-programming combinations

我用 (Int, Int, Int) 类型的元组表示了一个 3D 坐标

为了获得坐标的直接邻居,我做了这样的事情:

neighbours (x,y,z) =
    [(x',y',z') | x' <- [(x-1)..(x+1)], y' <- [(y-1)..(y+1)], z' <- [(z-1)..(z+1)], (x,y,z) /= (x',y',z')]

现在,我也需要使用 4D 坐标,我可以做一些非常类似的事情来获得具有 4 个元素的元组的邻居,它会起作用。但是,我需要复制我为 3D 坐标所做的所有函数,这次是为 4D 坐标。

为了避免这种情况,我想基本上用 Int 列表替换元组,现在对于 3D 坐标,例如 [9, 3, 0] 和 4D 坐标 [5, 1, 0, 1] 等等.

如何使用 Int 数组获取邻居?我尝试使用列表理解,但我没有找到解决方案。

PS:我是 Haskell 和函数式编程的新手

1 个答案:

答案 0 :(得分:2)

您可以递归进行,并根据 N-D 个邻居实现 (N+1)-D 个邻居。

本质上,如果您有一个 (N+1)-D 点 [x1,...,xNplus1],它的形式为 x1 : xs,其中 xs 是一个 N-D 点。因此,如果您已经知道 xs 的邻居列表,则可以将其转换为 x1 : xs 的邻居列表。

这是一个简单的尝试,应该几乎可以工作。

almostNeighbours :: [Int] -> [[Int]]
almostNeighbours []     = [[]]
almostNeighbours (x:xs) =
   [ x' : xs'
   | x' <- [x-1 .. x+1] , xs' <- almostNeighbours xs ]

请注意,我们确实将点本身包含在邻居列表中。如果不这样做,在递归情况下将不会产生足够的点。 (我建议说服自己确实如此。)

如果您不想要点本身,您可以稍后使用附加函数将其删除,而不会影响递归定义。

最后,请注意上面的代码可能不会像原始代码一样快,因为访问列表比访问元组慢。


次要选择:使用应用样式,我们可以稍微缩短代码。

almostNeighbours :: [Int] -> [[Int]]
almostNeighbours []     = pure []
almostNeighbours (x:xs) = (:) <$> [x-1 .. x+1] <*> almostNeighbours xs