2014-03-30 53 views
6

我試圖編寫一個函數,刪除列表中第二次出現的元素。 目前,我寫了一個函數,刪除第一個元素:在列表中刪除元素的第二次發生--Haskell

removeFirst _ [] = [] 
    removeFirst a (x:xs) | a == x = xs 
          | otherwise = x : removeFirst a xs 

爲出發點。但是,我不確定這個功能可以通過列表理解來完成。有沒有一種方法來實現這個使用地圖?

編輯:現在,我已經添加了調用第一

deleteSecond :: Eq a => a -> [a] -> [a] 
    deleteSecond _ [] = [] 
    deleteSecond a (x:xs) | x==a = removeFirst a xs 
        | otherwise = x:removeSecond a xs 

但是現在返回的列表中刪除一個元素的第一和第二次出現一個removeSecond功能。

+0

'map'返回與其輸入相同長度的列表,您正在查找比輸入短的列表。 – Cirdec

+0

你的代碼包含兩個函數:'removeFirst'和'deleteFirst'。我假設這是一個錯字? – Benesh

+0

是的,這是一個錯字,對不起。我會修改它。 – user3476396

回答

5

那麼,假設你有removeFirst - 如何尋找第一次出現,然後在其餘列表上使用removeFirst

removeSecond :: Eq a => a -> [a] -> [a] 
removeSecond _ [] = [] 
removeSecond a (x:xs) | x==a = x:removeFirst a xs 
         | otherwise = x:removeSecond a xs 
+0

哦,哇。我甚至沒有考慮過,謝謝。我仍然在努力學習Haskell,我發現即使是簡單的任務也非常具有挑戰性。 – user3476396

+0

不客氣。祝你好運! – Benesh

+0

如果我再打擾你一秒鐘,那麼刪除第二個元素仍然會刪除第一個元素。你知道避免這種情況的好方法嗎? – user3476396

3

你也可以實現這個摺疊。

removeNth :: Eq a => Int -> a -> [a] -> [a] 
removeNth n a = concatMap snd . scanl go (0,[]) 
    where go (m,_) b | a /= b = (m, [b]) 
        | n /= m = (m+1, [b]) 
        | otherwise = (m+1, []) 

,並在行動:

λ removeNth 0 1 [1,2,3,1] 
[2,3,1] 
λ removeNth 1 1 [1,2,3,1] 
[1,2,3] 

我用scanl而非foldlfoldr所以它可能既通過狀態由左到右和工作的無限列表:

λ take 11 . removeNth 3 'a' $ cycle "abc" 
"abcabcabcbc" 
+0

感謝ghci提示的絕妙主意...... –

0

這裏是使用List提供的功能的本能實現:

import List (elemIndices); 
removeSecond x xs = case elemIndices x xs of 
     (_:i:_) -> (take i xs) ++ (drop (i+1) xs) 
     _ -> xs 

removeNth n x xs = let indies = elemIndices x xs 
        in if length indies < n 
         then xs 
         else let idx = indies !! (n-1) 
          in (take idx xs) ++ (drop (idx+1) xs) 

注意:這個不能處理無限列表,其性能可能不適用於非常大的列表。

相關問題