List haskell列表中的唯一元素
好的,这可能会出现在序曲中,但是:有没有标准的库函数来查找列表中唯一的元素?为了澄清,我的(重新)实施是:List haskell列表中的唯一元素,list,haskell,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
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
我在上搜索(Eq a)=>[a]->[a]
第一个结果是(从列表中删除重复的元素)
Hoogle非常棒。来自
数据的nub
函数。List
(不,它实际上不在前奏曲中)确实做了一些您想要的事情,但它与您的独特的函数并不完全相同。它们都保留元素的原始顺序,但unique
保留最后一个顺序
每个元素的引用,而nub
保留第一个引用
您可以这样做,使nub
的行为完全像一样独特
,如果这很重要的话(尽管我感觉不是这样):
另外,nub
仅适用于小列表。
它的复杂性是二次的,所以如果你的列表可以包含数百个元素,那么它就开始变慢
如果将类型限制为具有Ord实例的类型,则可以使其更好地扩展。
nub
上的这种变化仍然保留列表元素的顺序,但其复杂性是O(n*logn)
:
事实上,它一直在向数据添加nubOrd
;也就是说,原始列表中出现多次的任何元素都不应包含在结果中
我可以提出另一个定义吗,独特的替代:
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 :: [Int] -> [Int]
unique xs = [x | (x,y) <- zip xs [0..], x `notElem` (take y xs)]
unique::[Int]->[Int]
唯一xs=[x |(x,y)在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"}
输出:
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 [] = []
unique (x:xs) = x:unique (filter ((/=) x) xs)
你的has
也是标准的;它只是flip elem
。或者甚至has xs=(`elem`xs)
@yatima2975为什么你要使用elem
作为中缀?@dopatraman因为elem
具有类型Eq a=>a->[a]->Bool
,所以将它用作中缀操作部分使xs
成为第二个参数。(`elem`xs)
被设计成(\x->elem x xs)
,这正是我们在这里想要的!此外,您可以像这样提供自己的相等函数:nubBy::(a->a->Bool)->[a]->[a]如果巴特有时间的话,我们可能会看到一个nubOrd,这在性能方面会更合理。值得一提的是,nub
函数来自Data.List
包。@Thomas:Data.List.Unique有一个sortUniq,这是您请求的“nubOrd”。我宁愿使用一个(Eq a,Hashable a)=>[a]->[a]这将更加合理,从性能角度来看……到目前为止,我真的很难理解如何有效地使用Hoogle,从未想过搜索我正在寻找的类型签名。有争议的是,最好将其作为一个集合,而不是首先使用列表。老实说:nub
对任何lis都不好t、 即使在包含两个元素的列表中,nubOrd也是。这有点像一个“映射筛”,类似于不纯的“散列筛”。函数类型签名中有一个输入错误。应该是Ord a
。此外,我发现nubOrd令人惊讶(或者不是)在我的例子中,它并不比nub好。它甚至更慢。可能是因为没有太多的重复值(虽然引入nub将运行时间减少了一半,但nub ord比nub慢了大约20%)@alternative,列表上的函数通常比集合上的等效函数更有用,因为它们可以维护项的顺序。这一点非常重要。事实上,这就是Data.List.Unique(Unique)的定义。虽然我个人从未使用过该用例,但“挤压列表以仅包含一个重复项”函数是许多操作的基础,它改变了元素的顺序。
Foo {id_ = 9, name_ = "Name"}
Foo {id_ = 9, name_ = "Gaby"}
Foo {id_ = 5, name_ = "Karl"}
Foo {id_ = 8, name_ = "Tim"}
unique [] = []
unique (x:xs) = x:unique (filter ((/=) x) xs)