我必须设计一个功能removeOrAdd :: a -> [a] -> [a]
。我直接的解决方案:
removeOrAdd :: Eq a => a -> [a] -> [a]
removeOrAdd x xs | x `elem` xs = [x' | x' <- xs, x' /= x]
| otherwise = x : xs
但是,我感觉自己正在做别人已经做过的事情。 Haskell中是否已有任何功能?
UPD::让我们将列表视为Set
,我们希望列表中没有多个x
,否则我们将其全部删除。>
答案 0 :(得分:3)
Haskell中是否已有任何功能?
据我所知,在Hoogle上进行搜索并没有立即列出该功能。我认为这很奇怪,因为通常一个人旨在添加或删除,但并非同时取决于条件。
我们可以通过使它更懒(可以使它在从未发生x
的无限列表上工作)来改进上述功能,并且在不对列表进行两次迭代的意义上说,效率更高。 。我们可以为此使用显式递归:
removeOrAdd :: Eq a => a -> [a] -> [a]
removeOrAdd x = go
where go [] = [x]
go (y:ys) | x == y = ys
| otherwise = y : go ys
因此,我们在此处遍历列表,一直进行迭代,直到找到等于y
的元素x
。在这种情况下,我们返回ys
,我们已经完成了,因为我们删除了该项目。如果不是,则通过递归到达列表的末尾,我们知道x
不属于列表,因此我们返回[x]
以添加该元素。因此,我们在此处将元素添加到列表的 end 。
如果列表已排序,我们可以将其插入正确的位置:
removeOrAdd :: Ord a => a -> [a] -> [a]
removeOrAdd x = go
where go [] = [x]
go (y:ys) | x == y = ys
| y > x = x : y : ys
| otherwise = y : go ys
因此,我们在这里将物品保持正确的顺序。