以下定义表示在网格上特定坐标处由彩色正方形组成的形状:
type AltShape = [Point]
data Point = P Colour (Int,Int) deriving Eq
data Colour = Black | Red | Green | Blue deriving Eq
我应该假设坐标始终为正,坐标(0,0)指向图片的左上角,并且y坐标向下增长
红色L形可以表示为
lShape = [P Red (0,0), P Red (0,1), P Red (0,2), P Red (1,2)]
表示这种形状的另一种方法是列表列表,每行一个列表:
type Shape = [Row]
type Row = [Square]
type Square = Maybe Colour
例如,上面的红色L形将由以下Shape类型的值表示:
lShape2 = [[x,o]
,[x,o]
,[x,x]] where x = Just Red
o = Nothing
我的任务是定义一个函数toShape :: AltShape -> Shape
,该函数将从AltShape转换为Shape。我还有另一个任务来定义函数fromShape :: Shape -> AltShape
,但其中data Shape = S [Row]
在其中。我发现这很简单,并这样写:
fromShape :: Shape -> AltShape
fromShape (S rows) = [ P c (x,y) | (y,row) <- index rows, (x,Just c) <- index row]
where index = zip [0..]
但是,我对此有更多麻烦。我首先创建函数
colourAndCoords :: Point -> (Colour,(Int,Int))
colourAndCoords ( P c (x,y) ) = (c,(x,y))
然后我创建了一个函数
coords :: [Point] -> [(Int,Int)]
coords ps = map snd (map colourAndCoords ps)
我的想法是将此列表与所有可能的协调的另一个列表进行比较,如果有匹配项,则添加正确的颜色,如果没有,则不添加任何内容。但是,我的老师说我太复杂了,应该考虑另一种解决方案。但是我很难想到一个。所以我想我的问题是更简单的方法是什么?我不是在寻求解决方案,只是在朝着正确的方向轻推。
感谢任何花时间阅读并回应的人!
如果我想出一个解决方案,我会回来并更新此线程。
答案 0 :(得分:1)
如果您想要一个有效的解决方案,accumArray
函数几乎可以完全满足您的需要(在计算了适当的界限之后)。
λ> arr = accumArray (const Just) Nothing ((0, 0), (2, 1)) [((y, x), c) | P c (x, y) <- lShape]
λ> arr
array ((0,0),(2,1)) [((0,0),Just Red),((0,1),Nothing),((1,0),Just Red),((1,1),Nothing),((2,0),Just Red),((2,1),Just Red)]
λ> elems arr
[Just Red,Nothing,Just Red,Nothing,Just Red,Just Red]
现在,问题已减少到split elements into groups。
λ> chunksOf 2 (elems arr)
[[Just Red,Nothing],[Just Red,Nothing],[Just Red,Just Red]]
对于真正的应用程序,您可能希望将其保留为数组,因为数组索引快速( O (1))而列表索引速度很慢( O ( n ))。
答案 1 :(得分:0)
如果不关心效率,则可以考虑采用这种方法:
Nothing
)。如果要关注效率,则可以考虑采用更复杂的方法:
[AltShape]
变成IntMap (IntMap Colour)
,例如使用this technique,它将y和x映射到颜色。toAscList
遍历占用的行;在每个列中,使用toAscList
遍历占用的列。您将需要使用[]
手动填充未占用的行,并使用Nothing
手动填充未占用的列。第二种方法的一个优点(或取决于您的目标,可能是不利的!)是它会自然产生“参差不齐”的Shape
,而忽略了后面的Nothing
。