在本练习中,我应该编写一个函数,它接收一个整数列表作为参数,并给出一个矩阵或列表列表。制作矩阵的要点是整数表示矩阵的每个列中的True
个数。例如
[2,4,1]
必须翻译为:
在系统中将其表示为列表列表:
[ [0,1,0], [0,1,0], [1,1,0], [1,1,1] ]
由于按列操作矩阵(列表列表)并不容易,我使用了一个技巧并使用transpose
将矩阵向左旋转了90度,这使得矩阵如下所示: / p>
然后我开发了以下算法来解决问题:
maximum xs
的列表(每个列表的长度等于列表中的最大元素)True
。False
我试图实现两个解决方案,但每个解决方案都有一个我无法解决的问题:
这个适用于第一个元素,但我不知道如何将它应用于输入列表的所有元素
listToMatrix x = (replicate ((maximum x) - (head x)) False) ++ (replicate (head x) True)`
这适用于所有元素但不能保留内部列表的长度,因此列表的长度不同。
listToMatrix lst@(x:xs) = ((replicate ((maximum lst) - x) False) ++ (replicate x True)) : listToMatrix xs`
问题1 :如何使用最少的更改使这些功能正常工作?
问题2 :更优雅,更紧凑的解决方案?
P.S。我在矩阵中使用了1和0来使它们更具可读性,但它们实际上是真和假
答案 0 :(得分:3)
我会使用以下方法,与您的方法兼容。
正如您所建议的那样,我们最后使用transpose
,因为转置矩阵看起来更容易生成。
f :: [Int] -> [[Bool]]
f xs = transpose (...)
然后,xs
的每个元素都必须生成一个新行。我们可以使用列表推导(在下面完成),也可以使用map
。
f :: [Int] -> [[Bool]]
f xs = transpose [ row x | x <- xs ]
where row :: Int -> [Bool]
row x = ...
根据您的建议,我们还需要maximum
来生成每一行,因此我们只计算一次:
f :: [Int] -> [[Bool]]
f xs = transpose [ row x | x <- xs ]
where m = maximum xs
row :: Int -> [Bool]
row x = ... -- we know x and m, we need m-x Falses and x Trues
现在,您只需要调整代码。
答案 1 :(得分:3)
我就是这样做的:
toMatrix' :: [[Bool]] -> [Int] -> [[Bool]]
toMatrix' acc xs
| or bools = toMatrix' (bools : acc) (map pred xs)
| otherwise = acc
where bools = map (> 0) xs
toMatrix :: [Int] -> [[Bool]]
toMatrix = toMatrix' []
简单明了。无需转置。
这是我的程序的可视化。我将0
和1
分别用于False
和True
。
toMatrix [2,4,1] = toMatrix' [] [ 2, 4, 1]
= toMatrix' [[1,1,1]] [ 1, 3, 0]
= toMatrix' [[1,1,0],[1,1,1]] [ 0, 2,-1]
= toMatrix' [[0,1,0],[1,1,0],[1,1,1]] [-1, 1,-2]
= toMatrix' [[0,1,0],[0,1,0],[1,1,0],[1,1,1]] [-2, 0,-3]
= [[0,1,0],
[0,1,0],
[1,1,0],
[1,1,1]]
当我们致电toMatrix' acc xs
时,我们首先计算bools = map (> 0) xs
。如果bools
的所有元素都是False
,那么我们就完成了。我们简单地返回acc
。否则,我们会将bools
添加到acc
的开头,并从xs
的每个元素中减去一个。冲洗并重复。
无需跟踪xs
的最大元素,也无需转置矩阵。简单。