【问题标题】:Haskell Remove duplicates from listHaskell 从列表中删除重复项
【发布时间】:2015-06-30 23:47:08
【问题描述】:

我是 Haskell 的新手,我正在尝试使用以下代码从列表中删除重复项。但是,它似乎不起作用。

compress []     = []
compress (x:xs) = x : (compress $ dropWhile (== x) xs)

我尝试了一些搜索,所有建议都使用 foldr/map.head。有没有基本结构的实现?

【问题讨论】:

  • 提示:你的想法完全正确,除了 dropWhile 是错误的函数。 dropWhile 删除列表中的每个元素直到它遇到== x 的元素;你需要一些东西来删除这样的每个元素。
  • 关于这个主题的讨论很好here
  • 请注意,有一个名为 nub 的内置模块来自 Data.List 模块。
  • @TikhonJelvis 你确定吗? GHCi 给dropWhile (==1) [1,1,1,2,3,1,4,5,6] ==> [2,3,1,4,5,6]
  • 哦,是的,完全搞反了,对不起!无论哪种方式,dropWhile 都不是正确的函数。

标签: haskell


【解决方案1】:

我认为您在代码中提到的问题是您当前的实现只会删除相邻的重复项。正如在评论中发布的那样,内置函数 nub 将消除每个重复项,即使它不相邻,并且只保留任何元素的第一次出现。但是既然你问如何用基本的结构来实现这样的功能,那么这个怎么样?

myNub :: (Eq a) => [a] -> [a]
myNub (x:xs) = x : myNub (filter (/= x) xs)
myNub [] = []

我向您介绍的唯一新功能是 filter,它根据谓词过滤列表(在这种情况下,删除该列表其余匹配项中存在的每个元素当前元素)。

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    首先,切勿在问题中简单地说“不起作用”。这留给读者检查它是编译时错误、运行时错误还是错误结果。

    在这种情况下,我猜这是一个错误的结果,像这样:

    > compress [1,1,2,2,3,3,1]
    [1,2,3,1]
    

    您的代码的问题在于它仅删除了连续 个重复项。第一对 1s 被压缩,但最后一个 1 并没有因此而被删除。

    如果可以,请提前对列表进行排序。这将使相等的元素接近,然后compress 做正确的工作。当然,输出的顺序会有所不同。如果需要,也有一些方法可以保持顺序(从zip [0..] xs 开始,然后排序,然后...)。

    如果您因为实在没有定义比较的实用方法而无法排序,而只能定义相等,那么请使用nub。请注意,这比排序和压缩效率低得多。这种性能损失是内在的:没有比较器,您只能使用效率低下的二次算法。

    【讨论】:

    • OP 的问题是关于实现 nub,而不是在库中找到它。对问题的讨论很有趣,但没有解决这个问题或 OP 对折叠和地图的困惑。
    【解决方案3】:

    foldrma​​p 是非常基本的 FP 结构。但是,它们非常笼统,很长时间以来我发现它们有点难以理解。 Tony Morris' talk Explain List Folds to Yourself对我帮助很大。

    在您的情况下,可以使用现有的列表函数(如 filter :: (a -> Bool) -> [a] -> [a] 和排除重复项的谓词)代替dropWhile

    【讨论】:

    • 大多数 Haskell 实现(当然是 GHC)中包含的 base 库包括高效的 Set 数据结构,当您添加到它们时会执行此操作。结合 Data.Set.fromListData.Set.toList 可以让你这样做,但我不认为库在这里使用你的意图。
    • 但是,将列表转换为集合将对元素进行排序并需要 Ord 约束。 Nub 只需要一个 Eq 约束并保留顺序。当然,set 选项在 O(n log n) 与 O(n^2) 时更有效。在这种情况下,可能不需要重新排序和/或附加约束。
    • @fgv 你觉得我的回答怎么样?我将 Set 建议保留为评论,因为它似乎与 OP 的意图不符。
    • 我认为您的回答将 OP 引导到正确的方向。从性能的角度来看,使用 set 或 map 的想法也很好,只是它会重新排序元素并放置 OP 可能不想要的额外约束......
    • 我完全同意。我很担心根据库使用发布建议 Data.Set.fromList 的评论,但是您对输出顺序的识别和输入的 Ord 约束是更重要的考虑因素,因为他们改变了 OP 函数的类型。
    猜你喜欢
    • 1970-01-01
    • 2018-08-29
    • 2013-04-13
    • 2019-09-30
    • 1970-01-01
    • 2014-09-30
    • 2011-01-13
    相关资源
    最近更新 更多