groupBy应该做什么?

时间:2014-04-06 18:09:57

标签: haskell haskell-platform

我用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平台中存在错误。

2 个答案:

答案 0 :(得分:6)

您的版本是 O n 2 ) - 在现实世界中使用 1

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

  

*主&GT; groupBy((==)`on`head')[“”,“”,“a”]

将产生你想要的结果。

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

  

*主&GT; groupBy((==)`on`head')$ DL.sort [“”,“a”,“”]

此复杂性仅为 O n log n )。


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

答案 1 :(得分:0)

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)。