我想在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
我的代码只生成一个组合,并且该组合必须是连续的,这不是我想要实现的
答案 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会更快。