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