[英]All the subsets of size N which satisfy a condition in Haskell
我想編寫一個函數,該函數接受一個列表並返回滿足給定條件的所有可能子集的列表。 例如,對於我想要具有[1,2,3,4]的所有3個大小的子集,但沒有包含2和3的任何子集。
$> func [1,2,3,4] 3
[[1,2,4],[1,3,4]]
要生成大小為NI的所有子集,請使用以下功能(在此處找到):
kCombinations :: [a] -> Integer -> [[a]]
kCombinations _ 0 = [[]]
kCombinations [] _ = []
kCombinations (x:xs) k = withHead ++ withoutHead
where withHead = map (x:) (kCombinations xs (k-1))
withoutHead = kCombinations xs k
我知道最簡單的解決方案是先生成所有組合,然后再使用過濾器功能。 但是對於更大的問題,例如kCombinations [1..30] 6
則要花很多時間才能完成。
您能告訴我在生成所有組合時如何過濾掉一些數據嗎?
這個問題很多,在這里可以找到各種方法的最新比較: 生成組合的技術比較
由於帶有備注,提到的最后一個方法( subsequencesOfSize
)非常高效。 我的機器上用ghci進行的時間比較:
length $ kCombinations [1..30] 6 - time: 2.73 secs
length $ subsequencesOfSize 6 [1..30] - time: 0.40 secs
為了解決您的原始問題(沒有2和3的子集),基本上有兩種方法可以計算答案:
-- import Data.List
answer1 = filter (\s -> not (elem 2 s && elem 3 s)) $ subsequencesOfSize 6 [1..30]
answer2 = map (2:) subs23 ++ map (3:) subs23 ++ subsequencesOfSize 6 nums'
where nums = [1..30]
nums' = [1..30] \\ [2,3]
subs23 = subsequencesOfSize 5 nums'
我的盒子上的時間(再次是ghci):
length answer1 -- 1.48 secs
length answer2 -- 0.36 secs
answer1
顯然是幼稚的方法; answer2
應用了一些基本的集合論,可以輕松地泛化不包含任何兩個數字的子集的計數-您可以決定它是否合法。
可以改善user5402提到的subsequencesOfSize
函數。 比較這個和這個 。 這是因為第二個版本中的(ln)
,所以subsequencesOfSize 3 [1..350]
等於subsequencesBySize [1..350] !! 347
subsequencesBySize [1..350] !! 347
,因此創建了許多未使用的列表。
當通過具有p xs
為true的性質的謂詞p
過濾子序列時,意味着all p (inits xs)
都是真實的,可以將謂詞整合到子序列的生成中,以實現更高的效率。 謂詞“不包含2和3”就是這種情況。
這是您想要的:
zapWith f xs [] = xs
zapWith f (x:xs) (y:ys) = f x y : zapWith f xs ys
filterCombs :: ([a] -> Bool) -> Int -> [a] -> [[a]]
filterCombs p n xs | n > length xs = []
filterCombs p n xs = go xs id !! n where
go [] ds = [[[]]]
go (x:xs) ds
| p (ds' []) = zapWith (++) ([] : map (map (x:)) with) without
| otherwise = without
where
ds' = ds . (x:)
with = go xs ds'
without = go xs ds
zapWith
故意並非詳盡無遺。 go
函數中的ds
是一個差異列表,其中包含所有先前的元素。 可以讀取go
這樣的:如果一個屬性p
保持用於<all previous elements of xs> ++ [x]
然后包括與組合x
和無x
,否則僅包括無x
。
一些例子:
conseq (x:y:xs) = succ x == y && conseq (y:xs)
conseq xs = True
main = do
print $ filterCombs (\xs -> any (`notElem` xs) [2,3]) 3 [1..5]
print $ filterCombs conseq 4 $ [1..8] ++ [8,7..1]
print $ filterCombs (all (<= 10)) 9 [1..5000]
版畫
[[1,2,4],[1,2,5],[1,3,4],[1,3,5],[1,4,5],[2,4,5],[3,4,5]]
[[1,2,3,4],[1,2,3,4],[2,3,4,5],[2,3,4,5],[3,4,5,6],[3,4,5,6],[4,5,6,7],[4,5,6,7],[5,6,7,8],[5,6,7,8]]
[[1,2,3,4,5,6,7,8,9],[1,2,3,4,5,6,7,8,10],[1,2,3,4,5,6,7,9,10],[1,2,3,4,5,6,8,9,10],[1,2,3,4,5,7,8,9,10],[1,2,3,4,6,7,8,9,10],[1,2,3,5,6,7,8,9,10],[1,2,4,5,6,7,8,9,10],[1,3,4,5,6,7,8,9,10],[2,3,4,5,6,7,8,9,10]]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.