好吧,我无法弄清楚如何在haskell中制作它。例如,我有这样的矩阵
[[1,2],[3,4]]
我希望生成一个列表列表,其中包含该矩阵的每个元素的所有可能邻居。
预期结果是:
[[1,2],[1,3],[1,4],[2,1],[2,3],[2,4],[3,1],[3,2],[3,4],[4,1],[4,2],[4,3]]
我知道如何使用每个单元格的邻居的绳索创建列表列表的函数:
pos how = [ (0+dx,0+dy) | dx <- [0..(how-2)], dy <- [0..how-1] ] :: [(Int,Int)]
neighbour (x,y) how = [ (x+dx,y+dy) | dy <- [-1..1], dx <- [-1..1],
x+dx >= 0, y+dy >= 0, x+dx<=how-2, y+dy <= how-1,
(x,y)/=(x+dx,y+dy) ] :: [(Int,Int)]
all_n how = [ p | x <- pos how, let p = neighbour x how ] :: [[(Int,Int)]]
但是我不能像我描述的那样改变它。
答案 0 :(得分:5)
让我勾勒出一个与你建议的方法截然不同的方法。在谈论邻居时,我会说 d - e 的邻居是元素 e方向 d 的一步。因此,例如,在矩阵[[1,2],[3,4]]
中,数字2
是数字1
的右邻居。我们需要使用一些库代码。
import Data.List
我们将从最简单的事情开始:让我们找到一维列表的右邻居。
rightList (x:y:rest) = (x,y) : rightList (y:rest)
rightList _ = []
我们可以通过不确定地选择矩阵的行并找到该行中的所有右邻居来找到矩阵中的所有右邻居。
right m = m >>= rightList
我们可以使用任何函数来查找邻居,并通过反转元组创建在另一个方向上查找邻居的函数。例如,左邻居与右邻居相同,但是交换了元组元素,所以:
swap (x,y) = (y,x)
co direction = map swap . direction
left = co right
下邻居怎么样?实际上,下邻居只是转置矩阵中的右邻居:
down = right . transpose
up = co down
下一个感兴趣的方向是右下邻居。这个有点棘手;我们要做的是并行地向下走两个列表,但是偏移一个。
downRight (xs:ys:rest) = zip xs (drop 1 ys) ++ downRight (ys:rest)
downRight _ = []
upLeft = co downRight
有一个最终方向,即右上邻居;如果我们将矩阵翻转过来,这些是右下邻居。
upRight = downRight . reverse
downLeft = co upRight
最后,为了形成所有邻居,我们可以不确定地选择相邻方向,然后找到该方向上的所有邻居。
allDirections = [right, left, up, down,
downRight, upLeft, upRight, downLeft]
neighbors m = allDirections >>= ($m)
输出不完全按照您指定的顺序排列,但我想这可能并不重要。
答案 1 :(得分:1)
为了纠正您现有的代码,我提供了一些问题,您可以通过深思熟虑的答案帮助您取得进展:
how-2
是一件奇怪的事。为什么2
是正确的数字减去?all_n
的类型很奇怪。为什么它是一个功能? (它的参数代表什么?)为什么它返回一个嵌套列表而不是一个扁平列表?(!!) :: [a] -> Int -> [a]
。)如果你有一个坐标列表,你知道如何为列表中的每个元素做这个吗? (提示:有一个函数map :: (a -> b) -> ([a] -> [b])
。)