我正在研究Programming Praxis上的一个简单问题:从列表中删除所有重复项而不更改顺序。假设元素属于Ord类,我想出了以下内容:
import Data.Set (Set)
import qualified Data.Set as Set
buildsets::Ord a => [a] -> [Set a]
buildsets = scanl (flip Set.insert) Set.empty
nub2::Ord a => [a] -> [a]
nub2 thelist = map fst $ filter (not . uncurry Set.member) (zip thelist (buildsets thelist))
正如你所看到的,构建集函数在很大程度上解决了我的问题,但是将所有内容组合在一起的最后一步(nub2)看起来非常可怕。有没有更简洁的方法来实现这一目标?
答案 0 :(得分:3)
由于我们必须过滤列表,我们应该使用一些集合来保存记录,我们不妨将filterM
与状态monad一起使用:
import qualified Data.Set as S
import Control.Monad.State.Strict
nub2 :: Ord a => [a] -> [a]
nub2 = (`evalState` S.empty) . filterM go where
go x = state $ \s -> if S.member x s
then (False, s)
else (True, S.insert x s)
如果我想对这个功能进行一些打击,我会发现以下内容:
import Control.Arrow (&&&)
nub2 = (`evalState` S.empty) . filterM (\x -> state (S.notMember x &&& S.insert x))
答案 1 :(得分:2)
简单的递归对我来说没问题。
> g xs = go xs S.empty where
> go [] _ = []
> go (x:xs) a | S.member x a = go xs a
> | otherwise = x:go xs (S.insert x a)
答案 2 :(得分:0)
直接基于Sassa NF的建议,但清洁度略有改变:
g x = catMaybes $ unfoldr go (Set.empty, x)
where
go (_,[]) = Nothing
go (s,(x:xs)) = Just (if Set.member x s then Nothing else Just x,
(Set.insert x s, xs))
答案 3 :(得分:0)
有时它会真正清理代码以提取和命名子项。 (在某些方面,这确实是Haskell评论代码的方式)
这比你上面所做的更啰嗦,但我觉得它更容易理解......
首先我从一些定义开始:
type Info=([Int], S.Set Int) --This is the remaining and seen items at a point in the list
item=head . fst --The current item
rest=fst --Future items
seen=snd --The items already seen
然后我添加了两个自描述辅助函数:
itemHasBeenSeen::Info->Bool
itemHasBeenSeen info = item info `S.member` seen info
moveItemToSet::Info->Info
moveItemToSet info = (tail $ rest info, item info `S.insert` seen info)
这个程序变成了:
nub2::[Int]->[Int]
nub2 theList =
map item
$ filter (not . itemHasBeenSeen)
$ takeWhile (not . null . rest)
$ iterate moveItemToSet start
where start = (theList, S.empty)
从下到上阅读(就像数据流一样),您可以轻松地看到它发生了什么:
start=(theList, S.empty)
,从完整列表开始,以及一个空集。
iterate moveItemToSet start
,重复将列表的第一项移动到集合中,将Data中的每次迭代保存在数组中。
takeWhile (not . null . rest)
- 当元素用尽时停止迭代。
filter (not . itemHasBeenSeen)
- 删除已经看过的项目。
map item
- 丢弃帮助者值....