删除列表中的重复对

时间:2018-01-14 22:55:39

标签: list function haskell tuples

我熟悉包含数字,字符或字符串的列表上的nub函数,但是 有人可以向我解释如何在nub列表中使用Data.List函数吗?

示例:

[('a', 3),( 'b', 2),('a', 1),('b', 4)]

[('a', 3),('b', 2)]

正如您所看到的,我想删除所有对中的键(键,值)已经在列表中的对。

4 个答案:

答案 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)]