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
Data.List
的nub
函数(不,它实际上并不在Prelude中)肯定会做你喜欢的事情,但是它和你的unique
function不太一样。 它们既保留了元素的原始顺序,也保留了每个元素的最后一个元素,而nub
保留了第一个元素。
你可以做到这一点,使nub
完全一样的unique
,如果这是重要的(虽然我有一种感觉不是):
unique = reverse . nub . reverse
另外, nub
只适用于小列表。 它的复杂性是二次的,所以如果你的列表可以包含数百个元素,它就会变得很慢。
如果您将types限制为具有Ord实例的types,则可以使其更好地缩放。 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 xs) xs go _ _ = []
实际上,已经提议将nubOrd
添加到Data.Set
。
我在Hoogle上search(Eq a) => [a] -> [a]
。
第一个结果是nub
(从列表中删除重复的元素)。
Hoogle很棒。
import Data.Set (toList, fromList) uniquify lst = toList $ fromList lst
我认为这个独特的应该返回一个只在原始列表中出现一次的元素列表; 也就是说,原始列表中不止一次出现的元素不应包含在结果中。
我可以build议一个替代的定义,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]
在Haskell中的algorithm创build一个唯一的列表:
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"}
另一种删除重复的方法是:
unique :: [Int] -> [Int] unique xs = [x | (x,y) <- zip xs [0..], x `notElem` (take y xs)]