我想创建一个具有以下定义的函数。
equivalent :: Eq a => (a -> a -> Bool) -> [a] -> [[a]]
等效的定义
三个整数x,y,p
x mod p == y mod p则x和y是等价的
否则x和y不相等。
案例:p = 3,
equivalent eq [1..10]
返回列表[[3, 6, 9], [1, 4, 7, 10], [2, 5, 8]]
eq
是一个需要两个整数并返回True / False的函数。
您会指导我如何在Haskell中创建函数吗?
答案 0 :(得分:2)
这是一个递归解决方案。
x
)。partition
将列表的其余部分拆分为 等同于x
(group
)的元素和不符合的元素相当于x
(others
)。x:group
是我们找到的第一个群组,然后我们会对others
进行审核。import Data.List (partition)
equivalent :: (a -> a -> Bool) -> [a] -> [[a]]
equivalent eq = go
where
go [] = []
go (x:xs) =
let (group, others) = partition (eq x) xs
in (x:group) : go others
证明使用:
>>> import Data.Function (on)
>>> equivalent ((==) `on` (`mod` 3)) [1..10]
[[1,4,7,10],[2,5,8],[3,6,9]]
顺便说一句,这是完成同样事情的另一种方式,我怀疑它更快:
>>> fmap (fmap snd) . groupBy ((==) `on` fst) . sort . fmap (\i -> (i `mod` 3, i)) $ [1..10]
[[3,6,9],[1,4,7,10],[2,5,8]]
答案 1 :(得分:0)
执行此工作的另一种方法是在列表上使用filter
和(\\)
(difference)函数。所以下面的递归代码就足够了。
groupByRemaindersOf :: Integral a => a -> [a] -> [[a]]
groupByRemaindersOf _ [] = []
groupByRemaindersOf p (x:xs) = let ys = x : filter (\y -> y `rem` p == x `rem` p) xs in ys : groupByRemaindersOf p (xs \\ ys)
*Main> groupByRemaindersOf 3 [1..10]
[[1,4,7,10],[2,5,8],[3,6,9]]
虽然这似乎比涉及sort
的任何算法都快,但我相信用Map
类型作为累加器折叠可能仍然比这更好。