【问题标题】:How to take only unique elements from a list?如何仅从列表中获取唯一元素?
【发布时间】:2019-12-17 10:58:09
【问题描述】:

我有一个列表,比如[1,2,3,4,3,2,4]。 我想将每个元素输出一次,例如[1,2,3,4]。 我怎样才能在 Haskell 中做到这一点?

【问题讨论】:

标签: list haskell functional-programming unique


【解决方案1】:

您可以使用nub :: Eq a => [a] -> [a] 作为uniqness 过滤器。然而,它需要 O(n2),因为它不使用像哈希集这样的数据结构。

例如:

Prelude Data.List> nub [1,2,3,4,3,2,4]
[1,2,3,4]

如果元素属于Hashable typeclass 的成员类型,您可以使用例如hashNub :: (Eq a, Hashable a) => [a] -> [a] 在O(n log n) 中执行唯一性过滤器: p>

Prelude ClassyPrelude> hashNub [1,2,3,4,3,2,4]
[1,2,3,4]

【讨论】:

  • 像hashNub,也有来自containers包的nubOrd and nubInt,它们分别使用Set和IntSet来实现相同的O(n log n) 复杂性。 (看起来hashNub 需要classy-prelude 或witherable 包。)
  • 还有nubOrdOn 和nubIntOn,让您可以对列表中的元素进行分类,并且只取每个类别中的第一个。
【解决方案2】:

您可以使用 Data.set 对集合进行操作:

import qualified Data.Set as Set
lst = [1,2,3,4,1,2,3]
y =  Set.fromList lst

输出是:

y
=> fromList [1,2,3,4]

【讨论】:

    【解决方案3】:

    有一个 nub 函数正是为此而生的。但是,它的复杂度为 O(n^2),不太好。如果是数字(或任何 Ord 类型),您可以像这样创建自己的 unique 函数:

    unique :: Ord a => [a] -> [a]
    unique = map head . group . sort
    

    您需要导入Data.List。 它的作用是这样的:

    sort [1,2,3,1,2] -> [1,1,2,2,3]        -- to order the elements
    group [1,1,2,2,3] -> [[1,1],[2,2],[3]] -- to group equal ones
    map head [[1,1],[2,2],[3]] -> [1,2,3]  -- to take first of groups
    

    这有 O(n log n) 的复杂度,这是一种更好的方式。

    【讨论】:

    • 或者只是nubOrd?
    • @JosephSible-ReinstateMonica 左右:)
    【解决方案4】:

    基本上,由于 Haskell 列表中的 sorting 非常快(最佳情况 O(n) 最坏情况 O(nlogn) 我们可能会先使用排序,然后折叠以获得有效的解决方案,并获得排序结果的额外效果,如果这将是有益的。

    以下代码用于最少的cons 操作;

    Prelude Data.List
    λ> :{
    λ| foldr (\e rs -> case rs of
    λ|                 []     -> [e]
    λ|                 (x:xs) -> if x == e then rs else e:rs) [] $ sort [8,8,4,3,2,3,3,2,1,8,3,5]
    λ| :}
    [1,2,3,4,5,8]
    

    下面是 @Joseph Sible-Reinstate Monica 指出的增强懒惰。

    Prelude Data.List
    λ> :{
    λ| foldr (\e rs -> e : case rs of
    λ|                 []     -> []
    λ|                 (x:xs) -> if x == e then xs else rs) [] $ sort [8,8,4,3,2,3,3,2,1,8,3,5]
    λ| :}
    [1,2,3,4,5,8]
    

    【讨论】:

    • @Joseph Sible-Reinstate Monica 感谢您的编辑,但如果我没记错的话,这个版本似乎对源列表的每个项目进行 cons 操作,而前一个版本对结果的每个项目执行一次 cons如果有重复,列表(有时要短得多)。
    • 是的,我想这里有一些权衡,即更早地产生结果与分配更少的结果。我个人更喜欢前者,但如果您不是粉丝,请随时恢复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    • 2017-08-11
    • 2021-07-20
    • 1970-01-01
    相关资源
    最近更新 更多