简体   繁体   English

删除List中元素的第二次出现 - Haskell

[英]Delete Second Occurence of Element in List - Haskell

I'm trying to write a function that deletes the second occurrence of an element in a list. 我正在尝试编写一个删除列表中第二次出现的元素的函数。 Currently, I've written a function that removes the first element: 目前,我编写了一个删除第一个元素的函数:

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

as a starting point. 作为一个起点。 However,I'm not sure this function can be accomplished with list comprehension. 但是,我不确定这个功能是否可以通过列表理解来完成。 Is there a way to implement this using map? 有没有办法使用地图实现这个?

EDIT: Now I have added a removeSecond function which calls the first 编辑:现在我添加了一个removeSecond函数调用第一个

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

However now the list that is returned removes the first AND second occurrence of an element. 但是现在返回的列表将删除元素的第一次和第二次出现。

Well, assuming you've got removeFirst - how about searching for the first occurence, and then using removeFirst on the remaining list? 好吧,假设你有removeFirst - 如何搜索第一次出现,然后在剩余列表中使用removeFirst

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

You could also implement this as a fold. 您也可以将其作为折叠实现。

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, [])

and in action: 并在行动:

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

I used scanl rather than foldl or foldr so it could both pass state left-to-right and work on infinite lists: 我使用scanl而不是foldlfoldr所以它可以从左到右传递状态并在无限列表上工作:

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

Here is an instinctive implementation using functions provided by List : 这是使用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)

Note: This one cannot handle infinite list, and its performance may not be good for very large list. 注意:这个不能处理无限列表,并且它的性能可能不适合非常大的列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM