我需要编写一段代码,删除列表中第一次出现的给定元素。到目前为止,我只设法使代码删除了给定元素的每次出现。
她是我现在的代码:
rem2 :: Eq a => [a] -> a -> [a]
rem2 xs y = [x | x <- xs, x /= y]
如果我尝试:
rem2 "hello" 'l'
代码将返回" hero ",而我希望它返回" hero "。有人能帮帮我吗?
您可以在这里使用递归。如果到达列表的末尾,则返回空列表(1);如果给你一个非空列表(x:xs)
,并且列表的头部x
与我们正在寻找的项目(2)匹配,我们返回列表的尾部xs
;如果项目不匹配(3),我们产生x
并递归到列表的尾部xs
。
这个函数看起来像:
rem1 :: Eq a => [a] -> a -> [a]
rem1 ls y = go ls
where go [] = … -- (1)
go (x:xs) | … = … -- (2)
| otherwise = … -- (3)
我把…
部分的实现留作练习。
delete
的简化定义:
delete :: a -> [a] -> [a]
delete _ [] = []
delete x (y:ys) = if x == y then ys else y : delete x ys
在实际库中使用更通用的函数deleteBy
。这是源代码。
找到了一个可能的解决方案,但不是我想要的。解决方案如下:
import Data.List
rem1 :: Eq a => [a] -> a -> [a]
rem1 xs y = delete y xs
所以如果有人有一个不包括内置功能的解决方案,我很乐意听到你的声音。
下面是一个好奇心的解决方案,您可以使用列表推导式:
remfst :: Eq a => a -> [a] -> [a]
remfst a xs
| (j:_) <-
[ i | (x,i) <- zip xs [0..], i <- [i | x == a]]
= [ x | (x,i) <- zip xs [0..], x <- [x | i /= j]]
remfst _ xs = xs
是"恶心"吗?在生产代码中,当然可以。在这里,这只是一些值得思考的事情。
现在我们有
> remfst 'l' "helalo"
"healo"