我希望在列表列表中更改(1到0)的函数,当该行/列中的1的数量不均匀时。我已经完成了这些功能:
1)看看列表中的行是否是偶数:
parityLine :: [[Int]] -> [Bool]
parityLine [] =[]
parityLine (x:xs)
|sum(x) `mod` 2 == 0 = True:(parityLine(xs))
|otherwise = False:(parityLine(xs))
2)对列表列表中的相应元素求和:
sumPositions :: [[Int]] -> [Int]
sumPositions [] = []
sumPositions (x:xs) = foldl (zipWith (+)) (repeat 0) (x:xs)
3)看看列表中的列是否是偶数:
parityColumn :: [Int] -> [Bool]
parityColumn [] = []
parityColumn (x:xs)
|head(x:xs) `mod` 2 == 0 = True:parityColumn(xs)
|otherwise = False:parityColumn(xs)
4)操作或两个布尔列表:
bol :: [Bool] -> [Bool] -> [[Bool]]
bol [] _ = []
bol (x:xs) (y:ys)= (map (||x) (y:ys)):(bol xs (y:ys))
5)正确清单:
correct :: [[Int]] -> [[Bool]]
correct [] = []
correct (x:xs)=(bol(parityLine (x:xs))(parityColumn(sumPositions(x:xs))))
所以我想要的是将函数correct
更改为[[Int]] - > [[Int]]来执行此操作:
My Int list(x:xs) With my correct function applied
[[0,0,1,1], [[True,True,True,True],
[1,0,1,1], [True,True,False,True],
[0,1,0,1], [True,True,True,True]
[1,1,1,1]] [True,True,True,True]]
现在我可以看到在第二行的第三列,False,所以我必须纠正那个数字1才能得到1的偶数。如果该列表中有多个False,我只想更正其中一个。
因此,我希望函数correct
返回:
[[0,0,1,1],
[1,0,0,1],
[0,1,0,1],
[1,1,1,1]]
感谢。
答案 0 :(得分:2)
我会给出一个从你所在的地方而不是从头开始的答案,所以我们这样做的方式比我的方式更多。
首先让我们为一个元素做:
leaveIf :: Bool -> Int -> Int
leaveIf yes 0 = if yes then 0 else 1
leaveIf yes 1 = if yes then 1 else 0
(你可以使用防护装置,但我的手机没有竖条字符!)
接下来我们可以列出一个列表:
edit :: [[Bool]] -> [[Int]] -> [[Int]]
edit boolss intss = zipWith (zipWith leaveIf) boolss intss
编辑:您只想更改一个,因此我们需要一种方法将后续的False
转换为True
s:
makeTrue :: [Bool] -> [Bool]
makeTrue xs = map (const True) xs
我使用了函数const :: a -> b -> a
。例如,const 5 'c'
只是5
。我可以将该定义缩短为makeTrue = map (const True)
。一旦你习惯于这样思考,你会发现更短的版本更清晰。
oneFalse :: [[Bool]] -> [[Bool]]
oneFalse [] = []
oneFalse (xs:xss) = let (trues,falses) = break (==False) xs in
case falses of
[] -> trues:oneFalse xss
(False:others) -> (trues ++ False : makeTrue others) : map makeTrue xss
(==False)
可以更简单地写成not
,但也许不太清楚。
所以例如
> oneFalse [[True,True,True,True],[True,False,True,False],[True,False,False,True]]
[[True,True,True,True],[True,False,True,True],[True,True,True,True]]
所以现在我们可以
editOne :: [[Bool]] -> [[Int]] -> [[Int]]
editOne boolss intss = zipWith (zipWith leaveIf) (oneFalse boolss) intss
答案 1 :(得分:2)
AndrewC已经提供了一个解决方案,它改变了与1
s相对应的所有 False
。如果我们只想更正第一个,我们必须找到zipWith
的替代品:
leaveIf ok x = if ok then x else 1 -x
-- Varianto of zipWith, which changes at most one element of the list
modFirst :: Eq b => (a -> b -> b) -> [a] -> [b] -> [b]
modFirst _ [] _ = []
modFirst _ _ [] = []
modFirst f (x:xs) (y:ys) = z : if y == z then modFirst f xs ys else ys
where z = f x y
edit :: [[Bool]] -> [[Int]] -> [[Int]]
edit boolss intss = modFirst (modFirst leaveIf) boolss intss
correct' :: [[Int]] -> [[Int]]
correct' xss = edit (correct' xss) xss
结果是不一定是所有行/行包含偶数1的列表列表:
correct' [[0,1,0],[1,1,1],[0,1,0]] = [[1,1,0],[1,1,1],[0,1,0]
您需要迭代几次,直到所有错误都得到修复(即计算固定点)。
我想补充一点,原始程序可以简化一点(不改变你的算法):
parityLine :: [[Int]] -> [Bool]
parityLine = map (even . sum)
parityColumn :: [Int] -> [Bool]
parityColumn = map even
sumPositions :: [[Int]] -> [Int]
sumPositions = foldl (zipWith (+)) (repeat 0)
bol :: [Bool] -> [Bool] -> [[Bool]]
bol xs ys = map (\x -> map (||x) ys) xs
correct :: [[Int]] -> [[Bool]]
correct xs = bol (parityLine xs) (parityColumn $ sumPositions xs)