Haskell函数,输出输入列表中添加到输入数字的所有组合

时间:2016-03-29 16:54:07

标签: list haskell recursion

我想在haskell中编写一个函数,它将整数列表和一个整数值作为输入,并输出包含加起来输入整数的元素组合的所有列表的列表。

例如:

myFunc [3,7,5,9,13,17] 30 = [[13,17],[3,5,9,13]]

尝试:

myFunc :: [Integer] -> Integer -> [[Integer]]
myFunc list sm = case list of
    [] -> []
    [x]
        | x == sm -> [x]
        | otherwise -> []
    (x : xs)
        | x + myFunc xs == sm -> [x] ++ myFunc[xs]
        | otherwise -> myFunc xs

我的代码只生成一个组合,并且该组合必须是连续的,这不是我想要实现的

4 个答案:

答案 0 :(得分:2)

编写一个函数来创建所有子集

f [] = [[]]
f (x:xs) = f xs ++ map (x:) (f xs)

然后使用过滤器

filter ((==30) . sum) $ f [3,7,5,9,13,17]

[[13,17],[3,5,9,13]]

正如@Ingo所建议的那样,你可以在生成列表时修剪它,例如

f :: (Num a, Ord a) => [a] -> [[a]]
f [] = [[]]
f (x:xs) = f xs ++ (filter ((<=30) . sum) $ map (x:) $ f xs)

应该比生成所有2 ^ N个元素更快。

答案 1 :(得分:2)

另一种方法是使用右折:

fun :: (Foldable t, Num a, Eq a) => t a -> a -> [[a]]
fun = foldr go $ \a -> if a == 0 then [[]] else []
    where go x f a = f a ++ ((x:) <$> f (a - x))

然后,

\> fun [3,7,5,9,13,17] 30
[[13,17],[3,5,9,13]]

\> fun [3,7,5,9,13,17] 12
[[7,5],[3,9]]

这种方法的一个优点是它创建任何列表,除非它累加到所需的值。 然而,基于过滤的方法将创建所有可能的子序列列表,仅在过滤步骤中丢弃大部分子列表。

答案 2 :(得分:1)

您可以使用subsequences中的Data.List为您提供所有可能的值组合,然后根据您添加到30的要求进行过滤。

myFunc :: [Integer] -> Integer -> [[Integer]]
myFunc list sm =
  filter (\x -> sum x == sm) $ subsequences list

答案 3 :(得分:1)

这是一个替代解决方案的想法:生成一个总计目标数量的列表列表,即:

[30]
[29,1]
[28,2]
[28,1,1]
...

然后才过滤那些可以从您给定列表中构建的内容。

Pro:可能要快得多,特别是如果您的输入列表很长且目标数量相对较小,那么加数列表的列表比输入列表的子集列表小得多。

Con:仅在游戏中没有0时才有效。

最后,你可以同时做两种方式并编写一个函数,根据一些输入列表和目标数字来决定哪个algorthm会更快。