2014-07-26 47 views
1

我試圖定義發現鄰居數之間的最小距離名單上哈斯克爾:鄰居數之間最小距離列表

像這樣一個functino上:

minNeighborsDistance [2,3,6,2,0,1,9,8] => 1 

我的代碼看起來像這樣:

minNeighborsDistance [] = [] 
minNeighborsDistance (x:xs) = minimum[minNeighborsDistance xs ++ [subtract x (head xs)]] 

雖然這似乎運行,一旦我進入一個列表,我收到一個異常錯誤。

我是新來的Haskell我很感謝在這個問題上的任何幫助。

+0

您將在空例中返回一個列表...而您的示例將返回一個數值。你的意思是返回0還是「Nothing」?看起來你想用一個「neighborsDistance」函數來解決這個問題,你可以應用最小值,最大值等。(也許'neighborsDistance [1 2 4] =只是[1 2]',比如'neighborsDistance [ 1] = Nothing')*(我剛剛在閱讀Haskell的初學者問題,開始......)* – HostileFork

+0

只是另一個小提示:用y代表一個元素到列表幾乎總是更高效: '而不是附加'++ [y]',如果你可以使用前者。 –

回答

6

如果傳遞一個單列表,然後minNeighborsDistance

  1. 這將無法在第一線匹配[],然後
  2. 它會成功匹配(x:xs)單值分配給x和空如xs,然後
  3. 當您嘗試訪問空列表的head時,它會引發錯誤。

此外,由於你叫minNeighborsDistance遞歸,那麼你將永遠最終稱它爲單列表,當你把它傳遞一個空列表除有關。

2

試試這個:

minDistance list = minimum (distance list) 
    where 
    distance list = map abs $ zipWith (-) list (tail list) 

distance計算列表的絕對值中減去自身1個職位轉移:

[2,3,6,2,0,1,9,8] -- the 8 is skipped but it does not make a difference 
- [3,6,2,0,1,9,8] 
= [1,3,4,2,1,8,1] 

minDistance現在只是得到結果列表中的最小元素。

+2

當你使用'abs'時,你確實不需要'正確'。 –

3

這就是我想出了:

minDistance l = minimum . map abs . zipWith (-) l $ tail l 
2

你的問題有點不清楚(一式簽名會真正幫助這裏),但如果你想計算列表中的相鄰元素之間的差異,然後找到最低的數字,我會說,最清晰的方式是使用一些額外的模式匹配:

-- Is this type you want the function to have? 
minNeighborsDistance :: [Int] -> Int 
minNeighborsDistance list = minimum $ go list 
    where 
     go (x:y:rest) = (x - y) : go (y:rest) 
     go anythingElse = []  -- Or just go _ = [] 

然而,這不會很給你你想要的答案,因爲實際的最小值你的例子列表將是-462。但是,這是一個簡單的辦法,只是採用abs

minNeighborsDistance :: [Int] -> Int 
minNeighborsDistance list = minimum $ go list 
    where 
     go (x:y:rest) = abs (x - y) : go (y:rest) 
     go anythingElse = [] 

我已經使用了輔助函數來計算從單元到單元的差異,那麼頂級定義該結果調用minimum得到最終的答案。

還有一個更簡單的方法,不過,如果你在Prelude,即zipWithmap開發的一些功能,並drop

minNeighborsDistance :: [Int] -> Int 
minNeighborsDistance list 
    = minimum  -- Calculates the minimum of all the distances 
    $ (maxBound:) -- Ensures we have at least 1 number to pass to 
        -- minimum by consing the maximum possible Int 
    $ map abs  -- Ensure all differences are non-negative 
    -- Compute the difference between each element. I use "drop 1" 
    -- instead of tail because it won't error on an empty list 
    $ zipWith (-) list (drop 1 list) 

所以合併成一條線沒有註釋:

minNeighborsDistance list = minimum $ (maxBound:) $ map abs $ zipWith (-) list $ drop 1 list 
+0

我有一個預感,你應該放棄那個'(0:)'> :) –

+0

@ØrjanJohansen爲什麼會這樣?它處理'list'是單例列表的情況。沒有它'minNeighborsDistance [1]'在空列表上引發異常。 – bheklilr

+0

因爲有了它,最低總是0 ... –