【问题标题】:What is groupBy supposed to do?groupBy 应该做什么?
【发布时间】:2014-04-06 18:09:57
【问题描述】:

我使用Data.List.groupBy 写了一些东西。它没有按预期工作,所以我最终编写了自己的groupBy 版本:毕竟我不确定Data.List 应该这样做(没有真正的文档)。

无论如何,我的测试使用我的groupBy 版本通过,而使用Data.List 失败。 我发现(感谢quickcheck)两个函数行为不同的情况,我仍然不明白为什么两个版本之间存在差异。 Data.List 版本有问题还是我的? (当然我的实现是幼稚的,可能不是最有效的方法)。

代码如下:

import qualified Data.List as DL
import Data.Function (on)
import Test.QuickCheck

groupBy' :: (a -> a ->  Bool) -> [a] -> [[a]]
groupBy' _ [] = []
groupBy' eq (x:xs) = xLike:(groupBy' eq xNotLike) where
    xLike = x:[ e | e <- xs, x `eq` e  ]
    xNotLike = [ e | e <- xs, not $ x `eq` e  ]

head' [] = Nothing
head'  (x:xs) = Just x

prop_a s = (groupBy' by s) == (DL.groupBy by s) where
    types = s :: [String]
    by = (==) `on` head'

ghc中运行quickCheck prop_a返回["", "a", ""]

*Main> groupBy' ((==) `on` head') ["","a",""]
[["",""],["a"]] # correct in my opinion
*Main> DL.groupBy ((==) `on` head') ["","a",""]
[[""],["a"],[""]] # incorrect.

发生了什么事?我不敢相信 haskell 平台中存在错误。

【问题讨论】:

  • groupBy 函数将列表分成几部分,例如 concat . groupBy f == id(以及其他法律)。

标签: haskell haskell-platform


【解决方案1】:

您的版本是 O (n2) - 在实际使用中速度可能会慢得无法接受1.

标准版本通过仅对等价的相邻元素进行分组来避免这种情况。因此,

*Main> groupBy ((==) `on` head') ["", "", "a"]

会产生你想要的结果。

使用groupBy 获得“通用分组”的一种简单方法是首先对列表进行排序,如果这对于数据类型是可行的。

*Main> groupBy ((==) `on` head') $ DL.sort ["", "a", ""]

这个复杂度只有On log n)。


1 这并不妨碍委员会将nub 指定为O (n2) ...

【讨论】:

  • 阅读groupBy 文档我意识到它确实是相邻的并且行为与我需要的不同:普通的group by。我确实可以做一个排序,但没有意识到这是必要的。我的版本没有假装在实数中可用,也没有对参数添加不必要的约束。除了明显的性能原因外,“Ord”约束在功能上是不必要的。
【解决方案2】:

Haskell 中的 Data.List.groupBy 是一个可用性错误!用户友好的 groupBy 应该是这样的:

groupByWellBehaved p = foldr (\x rest -> if null rest
                                     then [[x]]
                                     else if p x (head (head rest))
                                          then (x : head rest) : (tail rest)
                                          else [x] : rest) []

也许有更好的实现,但至少这是 O(n)。

【讨论】:

    猜你喜欢
    • 2011-02-23
    • 2015-09-17
    • 1970-01-01
    • 1970-01-01
    • 2014-10-26
    • 2011-06-20
    • 2012-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多