找到 9 个 3x3 "blocks" 个数独板 (Haskell)
Find 9 3x3 "blocks" of Sudoku board (Haskell)
我正在学习 Haskell,我决定着手开发一个小型数独求解器作为一个项目。我一直在使用 this assignment 作为指南,最近我在子问题 D2
上遇到了困难,该子问题是创建一个函数,该函数将从数独板(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 previous and possibly related SO question but I was not sure how to convert the pythonic solution to Haskell and whether or not I even should. I have also seen this 问题,但我的数独板结构有所不同。
可以找到我当前的所有代码here。另外,如果我能澄清任何事情,请告诉我。
首先,编写一个 groupBy3
函数,将列表按三个元素分组:
groupBy3 :: [a] -> [[a]]
然后使用以下操作链:
map groupBy3
transpose
concat
groupBy3
map concat
写在我的 phone 上,因此未经测试,但应该接近。
更新:我证实这有效:
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
不是这个问题的确切答案,但使用数组比使用列表要好得多。由于您需要更改元素,您可能需要使用 mutable arrays.
然后您可以将块实现为基本数组的 "views",只需对索引操作应用不同的偏移量即可,无需复制它们。
另一种方法,虽然可能不如公认的答案那么优雅:
map concat [(map (take 3 . drop i) . (take 3 . drop j)) grid | i <- [0, 3, 6], j <- [0, 3, 6]]
其中 grid
是 9x9 数独网格。
我正在学习 Haskell,我决定着手开发一个小型数独求解器作为一个项目。我一直在使用 this assignment 作为指南,最近我在子问题 D2
上遇到了困难,该子问题是创建一个函数,该函数将从数独板(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 previous and possibly related SO question but I was not sure how to convert the pythonic solution to Haskell and whether or not I even should. I have also seen this 问题,但我的数独板结构有所不同。
可以找到我当前的所有代码here。另外,如果我能澄清任何事情,请告诉我。
首先,编写一个 groupBy3
函数,将列表按三个元素分组:
groupBy3 :: [a] -> [[a]]
然后使用以下操作链:
map groupBy3
transpose
concat
groupBy3
map concat
写在我的 phone 上,因此未经测试,但应该接近。
更新:我证实这有效:
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
不是这个问题的确切答案,但使用数组比使用列表要好得多。由于您需要更改元素,您可能需要使用 mutable arrays.
然后您可以将块实现为基本数组的 "views",只需对索引操作应用不同的偏移量即可,无需复制它们。
另一种方法,虽然可能不如公认的答案那么优雅:
map concat [(map (take 3 . drop i) . (take 3 . drop j)) grid | i <- [0, 3, 6], j <- [0, 3, 6]]
其中 grid
是 9x9 数独网格。