haskell列表中的独特元素

时间:2010-06-23 01:46:11

标签: list haskell

好吧,这可能会出现在前奏中,但是:有没有标准的库函数来查找列表中的唯一元素?为了澄清,我的(重新)实施是:

has :: (Eq a) => [a] -> a -> Bool
has [] _ = False
has (x:xs) a
  | x == a    = True
  | otherwise = has xs a

unique :: (Eq a) => [a] -> [a]
unique [] = []
unique (x:xs)
  | has xs x  = unique xs
  | otherwise = x : unique xs

7 个答案:

答案 0 :(得分:91)

我在Hoogle上搜索了(Eq a) => [a] -> [a]

第一个结果是nub(从列表中删除重复的元素)。

Hoogle太棒了。

答案 1 :(得分:49)

来自nub的{​​{1}}函数(不,它实际上不在Prelude中)肯定会像您想要的那样,但它与您的Data.List函数不完全相同。它们都保留了元素的原始顺序,但unique保留了最后一个 每个元素的出现,而unique保留第一次出现。

你可以这样做,使nub行为与nub完全相同,如果这很重要(虽然我感觉不是):

unique

此外,unique = reverse . nub . reverse 仅适用于小型列表。 它的复杂性是二次的,所以如果你的列表可以包含数百个元素,它就会变慢。

如果将类型限制为具有Ord实例的类型,则可以使其更好地扩展。 nub上的此变体仍然保留了列表元素的顺序,但其复杂性为nub

O(n * log n)

事实上,将import qualified Data.Set as Set nubOrd :: Ord a => [a] -> [a] nubOrd xs = go Set.empty xs where go s (x:xs) | x `Set.member` s = go s xs | otherwise = x : go (Set.insert x s) xs go _ _ = [] 添加到nubOrd已经proposed

答案 2 :(得分:9)

import Data.Set (toList, fromList)
uniquify lst = toList $ fromList lst

答案 3 :(得分:4)

我认为unique应返回仅在原始列表中出现一次的元素列表;也就是说,不止一次出现的原始列表中的任何元素都不应包含在结果中。

我可以建议另一种定义,unique_alt:

    unique_alt :: [Int] -> [Int]
    unique_alt [] = []
    unique_alt (x:xs)
        | elem x ( unique_alt xs ) = [ y | y <- ( unique_alt xs ), y /= x ]
        | otherwise                = x : ( unique_alt xs )

以下是一些突出unique_alt和unqiue之间差异的例子:

    unique     [1,2,1]          = [2,1]
    unique_alt [1,2,1]          = [2]

    unique     [1,2,1,2]        = [1,2]
    unique_alt [1,2,1,2]        = []

    unique     [4,2,1,3,2,3]    = [4,1,2,3]
    unique_alt [4,2,1,3,2,3]    = [4,1]

答案 4 :(得分:1)

我认为这会做到的。

unique [] = []
unique (x:xs) = x:unique (filter ((/=) x) xs)

答案 5 :(得分:0)

删除重复项的另一种方法:

unique :: [Int] -> [Int]
unique xs = [x | (x,y) <- zip xs [0..], x `notElem` (take y xs)]

答案 6 :(得分:0)

Haskell中创建唯一列表的算法:

data Foo = Foo { id_ :: Int
               , name_ :: String
               } deriving (Show)

alldata = [ Foo 1 "Name"
          , Foo 2 "Name"
          , Foo 3 "Karl"
          , Foo 4 "Karl"
          , Foo 5 "Karl"
          , Foo 7 "Tim"
          , Foo 8 "Tim"
          , Foo 9 "Gaby"
          , Foo 9 "Name"
          ]

isolate :: [Foo] -> [Foo]
isolate [] = []
isolate (x:xs) = (fst f) : isolate (snd f)
  where
    f = foldl helper (x,[]) xs
    helper (a,b) y = if name_ x == name_ y
                     then if id_ x >= id_ y
                          then (x,b)
                          else (y,b)
                     else (a,y:b)

main :: IO ()
main = mapM_ (putStrLn . show) (isolate alldata)

<强>输出:

Foo {id_ = 9, name_ = "Name"}
Foo {id_ = 9, name_ = "Gaby"}
Foo {id_ = 5, name_ = "Karl"}
Foo {id_ = 8, name_ = "Tim"}