我熟悉包含数字,字符或字符串的列表上的nub
函数,但是
有人可以向我解释如何在nub
列表中使用Data.List
函数吗?
示例:
[('a', 3),( 'b', 2),('a', 1),('b', 4)]
到
[('a', 3),('b', 2)]
正如您所看到的,我想删除所有对中的键(键,值)已经在列表中的对。
答案 0 :(得分:8)
这是一种方式:
Prelude Data.List> nubBy (\(x,_) (x', _) -> x == x') [('a',1),('b',2),('b',3)]
[('a',1),('b',2)]
答案 1 :(得分:2)
你也可以使用'看到'状态变量,用于跟踪已添加的元素。这类似于nub
函数,但稍微调整以处理元组列表。它将结果累积到“看到过的”中。 list,并检查此列表中是否存在每个元组的第一个元素。如果在'中找到了',请不要添加它,否则将其添加到'看到'。
以下是一个例子:
removeDuplicate :: (Eq a) => [(a, b)] -> [(a, b)]
removeDuplicate lst = go lst []
where go [] seen = seen
go (x:xs) seen
| any (\(a, _) -> a == fst x) seen = go xs seen
| otherwise = go xs (seen ++ [x])
其工作原理如下:
*Main> removeDuplicate [('a', 3),( 'b', 2),('a', 1),('b', 4)]
[('a',3),('b',2)]
这也可以使用foldl
编写:
removeDuplicate' = foldl (\seen x -> if any (\(a, _) -> a == fst x) seen
then seen
else seen ++ [x]) []
最后一种过度杀戮的方法是事先用Data.List
中的sortBy
按照每个元组中的第一个元素对元素进行排序,然后将它们与groupBy
分组。然后,只需使用map()
从每个组中获取第一个元组,如下所示:
import Data.List
import Data.Function
removeDuplicate'' :: (Ord a) => [(a, b)] -> [(a, b)]
removeDuplicate'' xs = map head $ groupBy ((==) `on` fst) $ sortBy (compare `on` fst) xs
注意:建议nubBy
给出的答案是最简单的方法,我只是想建议其他方法来做到这一点。
此外,第三种方法使用Data.Function
中的on
,以便更轻松地进行分组和排序。
答案 2 :(得分:2)
与RoadRunner的答案一样,您可以将seen
实现为Set
,甚至将其包装在State
monad中。
module Main where
-- mtl
import Control.Monad.State (State, get, put, evalState)
-- containers
import Data.Set (Set, empty, insert, member)
removeDuplicates :: Ord a => [(a, b)] -> [(a, b)]
removeDuplicates xs = evalState (go xs) (empty, [])
where
go [] = do
(_, ys) <- get
return $ reverse ys
go (x:xs) = do
(s, ys) <- get
case member (fst x) s of
True -> go xs
False -> do
put $ (insert (fst x) s, x:ys)
go xs
main :: IO ()
main = do
let testData = [('a', 3),( 'b', 2),('a', 1),('b', 4)]
print $ removeDuplicates testData
再次,就像RoadRunner的回答一样 - 使用nubBy
来做到这一点。这种方法只是一种练习。
答案 3 :(得分:1)
我会做以下事情:
λ:> import Data.List (nubBy)
λ:> import Data.Function (on)
λ:> nubBy ((==) `on` snd) [('a',1),('b',2),('b',3)]
[('a',1),('b',2),('b',3)]