2013-03-21 74 views
9

Haskell中是否有任何庫函數可以讓我檢查列表是否連續排序?例如。 [1,2,3,4]有效,[1,2,3,10]無效。檢查是否連續排序列表

基本上我可以有一個列表,範圍從3到5個元素之間的任何地方,我試圖檢查該列表是否連續排序。

我嘗試(我不知道這是否是接近正確的方式,似乎是太多重複)

isSucc:: [Integer] -> Bool 
isSucc[]   = True 
isSucc(x:y:zs)  = 
    if (x+1) == y 
    then True && isSucc(y:zs) 
    else isSucc(y:zs) 

後,我有這個功能的工作,我打算使用它過濾列表(僅在列表內保留列表,並且僅在連續排序時)

回答

8

對此沒有標準功能。

這是你的函數的一個固定的版本,使其成爲通用的,去除多餘的條件,並添加缺少的:

isSucc :: (Enum a, Eq a) => [a] -> Bool 
isSucc [] = True 
isSucc (x:[]) = True 
isSucc (x:y:zs) | y == succ x = isSucc $ y:zs 
isSucc _ = False 
13

您可以使用技巧zipWith f xs (drop 1 xs)f應用於連續的列表元素對。 (注意:drop 1而不是tail,因爲如果該列表是空的,後者失敗!)

如果用<=替換f你會得到Bool值的列表。現在看看他們是否都是True

isSucc xs = and $ zipWith (<=) xs (drop 1 xs) 
+0

誤解問題的方法!但是,應該清楚如何改變'f'來使這個做你想做的。 – MathematicalOrchid 2013-03-21 08:24:54

+0

我從來沒有想過要做一個下降1。看起來像一個更好的解決方案來實現,但會減少1 xs比'(x:xs)'更昂貴? – rlhh 2013-03-21 08:35:16

+3

事實上,在這種情況下,'zipWith'與'zipWith'一起使用時'tail'很好,因爲命令'zipWith'的事故評估了它的參數。但是按順序評估它的參數並不是偶然的。 – Carl 2013-03-21 08:53:18

5

我更喜歡使用多一點可讀的解決方案相比,已被MathematicalOrchid提供一個。

首先我們將定義實用功能成對可能在許多不同的情況下是有用的:

pairwise xs = zip xs $ tail xs 

或更現代的方式:

import Control.Applicative ((<*>)) 

pairwise = zip <*> tail 

,然後用使用其他組合器:

isSucc xs = all (\(x,y) -> succ x == y) $ pairwise xs 
+1

這個解決方案並沒有做OP所需要的,並且與@MatemachicalOrchid所做的相同。看到我的評論他的回答:http://stackoverflow.com/questions/15542328/checking-to-see-if-a-list-is-ordered-successively/15542475#comment22025580_15542475 – 2013-03-21 13:13:09

+0

Iaroslav,你是完全正確的。我將編輯答案。 – Shaggie 2013-03-21 13:43:14

+0

我喜歡你如何使用一個函數的Applicative實例來編寫'<*>'。仍然試圖把我的頭圍繞它)Mindbending的東西! – 2013-03-21 15:41:58

0

Ther e是另一種方式,

isOrdered :: (Enum a, Eq a) => (a -> a -> Bool) -> [a] -> Bool 
isOrdered op (a:b:ls) = op a b && isOrdered op (b:ls) 
isOrdered op _ = True 

因此,

isSucc = isOrdered ((==) . succ) 
+0

這是不正確的--OP想要檢查元素是否連續,而不僅僅是它們的順序。你可以用'isSucc = isOrdered((==)。succ)' – kputnam 2013-03-21 13:59:08

+0

來解決這個問題。好的,感謝評論,我還沒有得到這個改進。 – zurgl 2013-03-21 14:07:46

+0

我很高興看到每一張海報都以和我一樣的方式誤解了這個問題。 :-) – MathematicalOrchid 2013-03-21 20:27:13

0

如果要檢查所有連續的差異等於一,你可以使用

isIncreasingByOne ::(公式一,民a)=> [a] - > Bool isIncreasingByOne = all(== 1)(zipWith( - )(tail xs)xs)

這適用於數字類型(因此Num a約束int),包括FloatDouble。比方說,如果你想檢查一個序列每次增加5個以上,也很容易適應。