2012-12-08 5 views
1

리스트의리스트에서 그 라인/컬럼의 수가 1이 아닐 때 (1에서 0으로) 변경하는 함수를 원한다. 나는 이러한 기능을 수행 한 :하스켈이리스트의 원소를 검색한다.

sumPositions :: [[Int]] -> [Int] 
sumPositions [] = [] 
sumPositions (x:xs) = foldl (zipWith (+)) (repeat 0) (x:xs) 

:

parityLine :: [[Int]] -> [Bool] 
    parityLine [] =[] 
    parityLine (x:xs) 
       |sum(x) `mod` 2 == 0 = True:(parityLine(xs)) 
       |otherwise = False:(parityLine(xs)) 

2) 목록 목록에서 해당 요소를 합계 : 목록에있는 줄도 또는하지 않은 경우

1) 본다

parityColumn :: [Int] -> [Bool] 
parityColumn [] = [] 
parityColumn (x:xs) 
    |head(x:xs) `mod` 2 == 0 = True:parityColumn(xs) 
    |otherwise = False:parityColumn(xs) 

4) 동작 또는 두 개의 부울 목록으로합니까 : 목록의 열은 짝수 또는하지 않은 경우 3) 본다 :

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을 변경하는 것입니다 [지능]] -> [[지능]] 않습니다이 :

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]] 

이제 제 2 행의 세 번째 열에 False가 표시되는 것을 볼 수 있습니다. 따라서 숫자 1을 정정해야만 1의 수가됩니다. 그 목록에 하나 이상의 False가있는 경우,이 중 하나만 수정하고 싶습니다.

[[0,0,1,1], 
    [1,0,0,1], 
    [0,1,0,1], 
    [1,1,1,1]] 

감사 :

은 결과, 그 기능을 correct 반환합니다.

+0

당신이 달성하고자하는 전체 결과는 무엇입니까? 당신의 설명은 단지 1의 수가 짝수가 아니지만 코드가 더 구체적인 목표를 제시한다면 1 (임의?) 1을 0으로 바꾸고 싶다고 말합니다. 모든 행과 열이 짝수 개의 행을 가지도록 입력을 수정 하시겠습니까? –

+0

또한 최소 요구 사항이 있습니까? 즉 가능한 한 적은 수의 1을 0으로 바꾸고 싶습니까? 왜냐하면, 지금 당신의 올바른 함수는 행복하게 십진수 십 ('[[0,1,0], [1,1,1], [0,1,0]')을 모두 거짓으로 바꿀 것이기 때문입니다. –

+0

matrix [[Bool]]이 False 인 위치에서 [[Int]]의 수를 변경하기 만하면됩니다. 목록 [[Bool]]에 둘 이상의 False가있는 경우 해당 목록 중 하나를 변경하고 싶습니다. – user1887556

답변

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 

편집 : 당신은 하나를 변경하려면, 그래서 우리는 엄마의 방법이 필요합니다 True들에 왕 이후 False들 :

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]] 

위해 우리는 AndrewC 이미 False의에 해당하는 모든1의 변경 솔루션을 준

editOne :: [[Bool]] -> [[Int]] -> [[Int]] 
editOne boolss intss = zipWith (zipWith leaveIf) (oneFalse boolss) intss 
+0

두 번째 줄과 세 번째 줄의 첫 번째 줄이 아니라 잘못된 번호를 잘못 입력했습니다. – user1887556

+0

해결책은 여전히 ​​정확한 것 같습니다. 'leaveIf'는 토글 링을보다 명확하게하기 위해 als'leaveIf yes x = if yes, then else else 1 - x'라고 쓸 수 있습니다. –

+0

귀하의 솔루션은 모든 숫자를 수정하고 그 중 하나를 수정하고 싶습니다. 미안하지만 언급하지 않았습니다. 어떻게해야합니까? 당신의 도움을 주셔서 감사합니다 – user1887556

2

수 있습니다. 우리는 첫 번째를 해결하려면, 우리는 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) 
관련 문제