我用 (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 和函数式编程的新手
答案 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