我试图根据元组的第一个值放弃第一次出现的元组。 我的计划是遍历元组列表,看看密钥是否存在于列表的其余部分,如果它存在,则返回列表的其余部分并查找其他重复项,否则将元素添加到返回列表中。
duplicate [(x,_):xs]= if (elem (x,_) xs )
then xs
else x ++ duplicate xs
我希望这是有道理的,谢谢你的帮助。
答案 0 :(得分:1)
对于一个相对简单但效率低下的(二次时间)解决方案,您可以执行以下操作:
removeFirstDuplicate :: Eq a => [(a, b)] -> [(a, b)]
removeFirstDuplicate [] = []
removeFirstDuplicate (hd@(x, _):tl) =
let
rest = removeFirstDuplicate tl
in
if x `elem` (map rest tl) then rest else hd:rest
它表示删除空列表的第一个副本是空列表。删除带有fst
x
的元组的第一个副本需要删除尾部的第一个副本,然后根据它是否在尾部,将第一个元组附加到结果中。
完整代码:
removeFirstDuplicate :: Eq a => [(a, b)] -> [(a, b)]
removeFirstDuplicate [] = []
removeFirstDuplicate xs@(hd@(x, _):tl) =
let
rest = removeFirstDuplicate tl
in
if x `elem` (map fst rest) then rest else hd:rest
main =
let
l = [(1, 'a'), (2, 'b'), (1, 'c'), (1, 'd'), (2, 'f')]
in
do
putStrLn $ show $ removeFirstDuplicate l
输出:
$ ghc duplicates.hs && ./duplicates
[(1,'d'),(2,'f')]
当然,应该可以在线性时间内强制求解,或者用平衡树在Θ(n log(n))中求解:首先迭代元组,并映射每个{ {1}}项到它出现的最后一个索引。然后再次迭代,并仅保留fst
项目在最后记录的索引的元组。
答案 1 :(得分:1)
我是Haskell的新手,所以如果我错了请纠正我。在这种类型的问题中,我的JavaScript本能告诉我使用Map或Hash。但是,当我检查Data.Map
库时,我注意到它是一个树实现,查找就像O(log n)。所以如果我使用sortOn
代替,我认为它的性能可能相似。任何进一步的信息都非常感谢。
所以我的解决方案是;
dropFirstDupe :: (Ord a, Eq a) => [(a,b)] -> [(a,b)]
dropFirstDupe [] = []
dropFirstDupe [t] = [t]
dropFirstDupe ts | fst t1 == fst t2 = dropFirstDupe (t2:tr)
| otherwise = t1 : dropFirstDupe (t2:tr)
where (t1:t2:tr) = sortOn fst ts
*Main> dropFirstDupe [(1,2),(3,6),(8,7),(1,5),(3,3),(7,9)]
[(1,5),(3,3),(7,9),(8,7)]
注意:如果存在超过2个重复项,则它将保留最后一个。
嗯,我想在上面的代码片段中,我在递归的每个回合中都运行sortOn
函数,这是完全没必要的。因此,上述代码的更高效版本应该是;
dropFirstDupe :: (Ord a, Eq a) => [(a,b)] -> [(a,b)]
dropFirstDupe [] = []
dropFirstDupe ts = dfd (sortOn fst ts)
where dfd [t] = [t]
dfd (t1:t2:tr) | fst t1 == fst t2 = dfd (t2:tr)
| otherwise = t1 : dfd (t2:tr)