2012-10-06 75 views
0

我試圖做一個函數,它在列表中,如果要素之一是否定的,那麼在該列表中等於其積極對應任何內容應改爲0 。例如,如果有一個-2列表,那麼所有2個在這一名單應改爲0哈斯克爾:模式與列表匹配

任何想法,爲什麼它僅適用於某些情況下,而不是別人?我不明白這是爲什麼,我已經看了好幾遍。

changeToZero [] = [] 
changeToZero [x] = [x] 
changeToZero (x:zs:y:ws) | (x < 0) && ((-1)*(x) == y) = x : zs : 0 : changeToZero ws 
changeToZero (x:xs) = x : changeToZero xs 

*主要> changeToZero [-1,1,-2,2,-3,3]

[-1,1,-2,2,-3,3]

*主要> changeToZero [-2,1,2,3]

[-2,1,0,3]

*主要> changeToZero [-2,1,2,3,2]

[-2,1,0,3,2]

*主要> changeToZero [1,-2,2,2,1]

[1,-2,2,0,1]

+1

表達式'X:ZS:Y:ws'是相當於'[x,zs,y] ++ ws'。因此,'zs'將始終是列表中的單個元素;它永遠不會是多個元素(或者沒有元素)。 –

+0

如果我想ZS是多個元素,將X:ZS:Y使其被認爲是多重的,而不是一個單一的元素?對不起,我盡力學習,因爲我是初學者! – user1670032

+0

恐怕不是。在表達式(或圖案)'一個:B','A'始終是一個單一元件和'B'始終是一個列表;表達式'a:b'相當於'[a] ++ b'。由於':'是右聯合的結果,這意味着在諸如'a:b:c:d'的表達式(或模式)中,最右邊的變量是「列表的其餘部分」,並且其他變量是個別元素。 –

回答

6

我覺得列表理解爲既清晰,更容易在這裏得到。

changeToZero xs = [if x > 0 && (-x) `elem` xs then 0 else x | x <- xs] 

如果你需要的東西更有效,你可以建立一套消極因素和檢查,而不是使用elem

import qualified Data.Set as Set 

changeToZero' xs = [if (-x) `Set.member` unwanted then 0 else x | x <- xs] 
    where unwanted = Set.fromList $ filter (< 0) xs 
+0

這是O(n^2)的方式 – jdevelop

+0

謝謝!我不知道你可以在if/else子句中使用列表理解。 (我是一個初學者,因爲你可以告訴,哈哈):) – user1670032

+0

這裏的Set方法比O(n^2)快得多。也許jdevelop是指elem方法。爲清晰起見+1。 – AndrewC

1

你不anctually記得你在列表中

import qualified Data.Set as S 

changeToZero :: [Int] -> [Int] 
changeToZero [] = [] 
changeToZero xs = reverse . snd $ foldl f (S.empty,[]) xs 
    where 
    f (negs,res) x | x < 0 = (S.insert (-x) negs, x:res) 
        | S.member x negs = (negs,0:res) 
        | otherwise = (negs,x:res) 
+0

不必要的複雜,看看基於哈姆馬爾解決方案的優雅列表理解 –

+1

它還是更高效,因爲用列表理解版本列表評估2次。沒有理由繼續下去。 – jdevelop

+0

謝謝你的迴應!我更喜歡只使用Data.List,但這也會起作用!我已經投了你的答案:) – user1670032

1

嘛發現了負的符號,構建從@jdevelop答案,如果負是爲了之前的正面出現,以算的話,你可以用一個傳過來的輸入構建的結果,而不需要扭轉這種局面:

import qualified Data.Set as S 
import Control.Monad.State 

changeToZero :: [Int] -> [Int] 
changeToZero xs = evalState (mapM f xs) S.empty where 
    f x | x < 0  = modify (S.insert (-x)) >> return x 
     | otherwise = gets (S.member x) >>= \hasNeg -> return $ if hasNeg then 0 else x 

通過這種方式,你可以得到一個答案

take 4 $ changeToZero $ 1 : (-2) : 3 : 2 : undefined 

在其他的解決方案將失敗。

**編輯**

這裏是同樣的事情,但沒有State單子,這使得它更易於理解:

changeToZero' :: [Int] -> [Int] 
changeToZero' = go S.empty where 
    go _ [] = [] 
    go s (x:xs) | x < 0  = x : go (S.insert (-x) s) xs 
       | S.member x s = 0 : go s xs 
       | otherwise = x : go s xs