2014-02-21 60 views
0

如何將一個列表拆分爲2個子列表,其中第一個子列表包含來自初始列表開始的元素並等於第一個元素,第二個子列表包含其他元素?我必須解決這個問題,而不使用前奏功能。將Haskell中的列表拆分成子列表

我的基本的解決方案是:

partSameElems :: [a] -> ([a],[a]) 
partSameElems [] = ([],[]) 
partSameElems (x:xs) = fstList (x:xs) scdList (x:xs) 
    where 
     fstList (x:y:xs) = if x == y then x:y:fstList xs {- I need to do Nothing in else section? -} 
     scdList (x:xs) = x:scdList xs 

例如: [3,3,3,3,2,1,3,3,6,3] -> ([3,3,3,3], [2,1,3,3,6,3])

現在,我可以提供我的版本的解決方案:

partSameElems :: Eq a => [a] -> ([a],[a]) 
partSameElems [] = ([],[]) 
partSameElems (x:xs) = (fstList (x:xs), scdList (x:xs)) 
where 
    fstList [] _ = [] 
    fstList (x:xs) el = if x == el then x:fstList xs el else [] 
    scdList [] _ = [] 
    scdList (x:xs) el = if x /= el then (x:xs) else scdList xs el 
+2

看起來你看起來並不像你在發佈之前嘗試了很多努力。不是學習的好方法。 – Nicolas

+0

@Nicolas我嘗試了一些,現在修復我的«解決方案» – zerospiel

回答

2

這是比較容易,如果你不嘗試兩次傳球。

parSameElems [] = ([], []) 
parSameElems lst = (reverse revxs, ys) 
    where (revxs, ys) = accum [] lst 
     accum xs [y] = ((y:xs), []) 
     accum xs (y1:y2:ys) | y1 == y2 = accum (y1:xs) (y2:ys) 
          | otherwise = ((y1:xs), (y2:ys)) 

不確定你可以在where子句中使用guard語法。由於你不能使用Prelude,你還必須自己實現反轉,但這很容易。

注意:我沒有真正運行這個。確保你嘗試並調試它。

此外,不要自己寫入類型簽名。讓ghci告訴你。你第一次嘗試就錯了。

+0

完美的作品!我在簽名時是否錯過了'Eq a =>'? – zerospiel

+0

我認爲在你的解決方案中沒有必要使用'reverse',因爲第一個子列表只包含等於元素 – zerospiel

+0

是的,'Eq'邊界缺失。關於逆向的好點。 –

0

我認爲「不訴諸前奏」功能意味着它是教育性的。鑑於它是對List數據的操縱,可能旨在處理遞歸。所以讓我們來強調這一點:

當輸入和輸出類型相同時,遞歸算法更易於表達。 我們寧可說,而不是一個列表[3,3,3,3,2,1,3,3,6,3],輸入數據由

  • 前面列表,但在這個階段,它是空的
  • 的餘數,在這個階段等於輸入[3,3,3,2,1,3,3,6,3]
  • 遞歸輸入是然後([],[3,3,3,2,1,3,3,6,3])

類型中央功能將是([a],[a]) -> ([a],[a])

現在,每次遞歸步驟將其餘的正面元素,無論是在前面的列表中把是否或停止遞歸(你達到最終狀態並能返回結果)

module SimpleRecursion where 
moveInFront :: (Eq a) => ([a],[a]) -> ([a],[a]) 
moveInFront (xs , [] ) =    (xs , []) 
moveInFront ([] , y:ys) =    moveInFront (y:[] , ys) 
moveInFront (x:xs , y:ys) = if x == y then moveInFront (y:x:xs , ys) 
             else (x:xs, y:ys) 

partSameElems :: (Eq a) => [a] -> ([a],[a]) 
partSameElems a = moveInFront ([],a) 

我們在這裏是一個經典的遞歸方案,與 - 停止條件(X/= Y) - 遞歸條款 - 的瑣碎案件

覆蓋

注: - 寫y:x:xs實際上顛倒了前名單,但因爲所有的值相等的結果是正確的 請不要在這樣的伎倆實際的程序中電子代碼,它會回來,最終咬你 - 該功能僅適用於Equatable數據(Eq a) =>的名單,因爲遞歸/停止條件是平等的測試==

0

另一種實現可以

​​

應該清楚它的功能。

> partition [3,3,3,3,2,1,3,3,6,3] 
([3,3,3,3],[2,1,3,3,6,3])