我在haskell中编写一个梳子函数 它需要做的是,当我提供一副纸牌时,给我每个组合的手可能从那个大小的牌组x
这是相关代码
combs :: Int -> [a] -> [[a]]
combs 0 _ = [[ ]]
combs i (x:xs) = (filter (isLength i) y)
where y = subs (x:xs)
combs _ _ = [ ]
isLength :: Int -> [a] -> Bool
isLength i x
| length x == i = True
| otherwise = False
subs :: [a] -> [[a]]
subs [ ] = [[ ]]
subs (x : xs) = map (x:) ys ++ ys
where ys = subs xs
然而,当我要求它计算梳子5 [1..52]时,例如一个完整的牌组中有5个牌,它不会提供结果,并且会长时间保持运行 有谁知道问题是什么以及如何加速这个算法?
答案 0 :(得分:3)
现在有点难以看到你想要做什么 - 但我猜你遇到的问题是你会过滤和绘制很多地方。
我认为获得所需内容的简单方法是:
module Combinations where
import Data.List (delete)
combs :: Eq a => Int -> [a] -> [[a]]
combs 0 _ = [[]]
combs i xs = [ y:ys | y <- xs, ys <- combs (i-1) (delete y xs) ]
使用delete
Data.List
它应该很懒,很快找到你的组合 - 当然所有都需要一段时间;)
λ> take 5 $ combs 5 [1..52]
[[1,2,3,4,5],[1,2,3,4,6],[1,2,3,4,7],[1,2,3,4,8],[1,2,3,4,9]]
它是那些递归组合算法之一,通过从所有卡y
中选择第一张卡xs
,然后recursivley得到s the rest of the hand
ys {{1}删除list-monad中的xs from the deck without the selected card
y:ys`(这里使用list-comprehensions)。
这是一个没有理解的版本,以防您的系统出现问题:
and then putting it back together
这个使用combs :: Eq a => Int -> [a] -> [[a]]
combs 0 _ = [[]]
combs i xs = do
y <- xs
ys <- combs (i-1) (delete y xs)
return $ y:ys
来按顺序对排序项目进行排序这样做可以删除与permutaion相关的重复项 - 为此工作Ord
应该是预排序!
注意 chi的版本正在使用更少的约束,也可能更具信息性 - 但我认为这很好,可读性很好,之前的版本也很好,所以也许它&#39;你感兴趣的。
我知道这不是Haskell / FP中经常做的事情,在那里你为最普遍和最抽象的案例而奋斗但是我形成了一个大多数人都在努力寻求可读性和理解的环境(不仅仅是为程序员编写代码)编译器) - 所以要温柔;)
xs
答案 1 :(得分:3)
要从i
中提取x:xs
项,您可以通过两种方式继续:
x
,并仅从i-1
xs
个元素
x
,并从i
xs
元素
因此,解决方案是:
comb :: Int -> [a] -> [[a]]
comb 0 _ = [[]] -- only the empty list has 0 elements
comb _ [] = [] -- can not extract > 0 elements from []
comb i (x:xs) = [ x:ys | ys <- comb (i-1) xs ] -- keep x case
++ comb i xs -- discard x case
顺便说一句,上面的代码也证明了#34;二项式系数的众所周知的递归公式。如果你参加过微积分课,你可能已经满足了这个公式。
让B(k,n) = length (comb k [1..n])
,我们有
B(k+1,n+1) == B(k,n) + B(k+1,n)
这只是上面代码最后一行的直接后果。