我正在学习Haskell,我决定将一个小型数独求解器作为一个项目。我一直在使用this assignment作为指导,我最近在子问题D2
上遇到了障碍,即创建一个可以从Sudoku板生成数独块(9个3x3网格)的函数(a 9x9网格)。
我开始编写以下代码,但我很快意识到这是一个糟糕的主意。这是一个笨重的代码,不是惯用的Haskell(在我看来),完全违反了DRY原则。
type Block = [Maybe Int]
data Sudoku = Sudoku [[Maybe Int]]
blocks :: Sudoku -> [Block]
blocks (Sudoku rs) = block1 : block2 : block3 : block4 : block5 : block6 : block7 : block8 : block9 : []
where block1 = [(rs!!0)!!0] ++ [(rs!!0)!!1] ++ [(rs!!0)!!2] ++ [(rs!!1)!!0] ++ [(rs!!1)!!1] ++ [(rs!!1)!!2]++ [(rs!!2)!!0] ++ [(rs!!2)!!1] ++ [(rs!!2)!!2]
block2 = ...
block3 = ...
...
我想知道如何编写一个更简洁和惯用的功能来完成任务?你将如何实现它?任何想法都表示赞赏!
我还咨询了this以前和可能相关的SO问题,但我不知道如何将pythonic解决方案转换为Haskell以及我是否应该。我也看到this问题,但我的Sudoku电路板结构不同。
我的所有当前代码都可以找到here。另外,让我知道我是否可以澄清任何事情。
答案 0 :(得分:2)
首先,编写一个groupBy3
函数,该函数按三个元素对列表进行分组:
groupBy3 :: [a] -> [[a]]
然后使用以下操作链:
map groupBy3
transpose
concat
groupBy3
map concat
写在我的手机上,所以它没有经过测试,但应该很接近。
更新:我确认这有效:
groupBy3 (a:b:c:ds) = [a,b,c] : groupBy3 ds
groupBy3 [] = []
groupBy3 as = [ as ] -- won't happen
boxes = map concat . groupBy3 . concat . transpose . map groupBy3
grid = [ [ [i,j] | j <- ['1'..'9'] ] | i <- ['a'..'i'] ]
test1 = boxes grid
答案 1 :(得分:0)
这个问题不是一个确切的答案,但你最好不要使用数组而不是列表。由于您需要更改元素,因此您可能希望使用mutable arrays。
然后你可以实现块作为&#34; views&#34;对于基本数组,只需对索引操作应用不同的偏移量,就不需要复制它们。
答案 2 :(得分:0)
另一种方法,虽然可能不如公认的答案那么优雅:
map concat [(map (take 3 . drop i) . (take 3 . drop j)) grid | i <- [0, 3, 6], j <- [0, 3, 6]]
其中grid
是9x9数独网格。