2011-04-08 137 views
0

我一直在試圖定義一個函數,給定一個整數和一個整數n列表,返回一個布爾值,指示n是否恰好在列表中出現一次。通過列表搜索

我有這個,但它不工作,我無法弄清楚

once :: [a] -> (a -> Bool) -> Bool 
filter _ [] = [] 
filter p (x:xs) 
    | p x  = x : filter p xs 
    | otherwise = filter p xs 

An example of what I want would be: 
Main> once [2,3,2,4] 2 
False 
Main> once [1..100] 2 
True 

回答

2
once :: (Eq a) => [a] -> a -> Bool 
once xs x = (== 1) $ length $ filter (== x) xs 
+0

感謝您的任何想法如何處理無限的列表? – John 2011-04-08 23:16:00

+0

約翰,你需要在列表中匹配它的長度,而不是像下面的答案那樣取長度。 – 2011-04-09 02:23:17

+1

我不認爲在一般情況下可以處理無限列表。如何知道確定性程序停止在'repeat 2'中尋找'1'? – acfoltzer 2011-04-09 02:34:06

2

好了,你可以過濾列表,然後看看有多少元素在得到的濾波器,對不對?

爲了讓你開始:

> filter (== 2) [1,2,3,4,5] 
[2] 

> filter (== 2) [1,2,3,4,5,2,2] 
[2,2,2] 

和你的列表中上下摺疊成一個布爾值,在這裏,在這裏我們測試如果列表中有三個元素的例子,返回一個布爾值:

> isThree (a:b:c:[]) = True 
> isThree _   = False 

所以它是構成這種功能只有很短的事情:

> isThree . filter (==2) 

或您的變種(如匹配對於長度爲1的列表)。

+0

我知道,但我只是不知道如何輸出到布爾值而不是列出匹配的內容。 – John 2011-04-08 21:34:32

+0

比較列表的長度與1? – 2011-04-08 21:48:59

+0

Once :: [a] - > a - > Bool filter(k)[a] If 1 John 2011-04-08 21:54:39

0

這裏是另一個版本:

once x = not . (\xs -> null xs || x `elem` tail xs) . dropWhile (/= x) 

--lambda hater version 
import Control.Applicative 
once x = not . ((||) <$> null <*> (elem x).tail) . dropWhile (/= x) 

當然不能包含零或一個X無限列表的交易,但它至少在x的出現了多次的情況下終止。

6

,因爲我以爲我以前的解決方案是醜陋的,我問another forum和得到這個作爲答案:

once :: Eq a => a -> [a] -> Bool 
once x = (== [x]) . filter (== x) 

我認爲你不能寫一個函數更漂亮,並在對比接受的答案是懶。

+1

+1用於終止第二次出現的x,而不是遍歷整個列表(「長度」)。 – Nefrubyr 2011-04-11 10:31:38

+0

Upvoted。教我新的東西。 – 2011-04-11 15:17:24

+0

* 1,但是如果確實存在第二個x並且它不是最後一個元素,則它只是更懶。說實話,應用這個函數的人必須假定整個列表都會被評估。 – Ingo 2011-04-12 16:59:57