我正在努力编写代码,这将计算int列表列表的总和。例如,如果我们考虑以下列表
[[1],[1,5],[7],[2,3,4]]
我们可以获得不同的可能总和,具体取决于我们每次选择的整数:
[11,12,13,15,16,17]
有人可以提供可能的方法(不需要代码)我能解决吗?
答案 0 :(得分:1)
以下是试图打破可读和希望可以理解的部分的步骤
fun sums xss =
let
fun extend xss y = map (fn xs => y :: xs) xss
fun extend' xss ys = foldl (fn (y, b) => extend xss y @ b) [] ys
fun extend'' xss = foldl (fn (xs,b) => extend' b xs) [[]] xss
fun sum xs = foldl op+ 0 xs
in
map sum (extend'' xss)
end
- sums [[1],[1,5],[7],[2,3,4]];
val it = [17,13,16,12,15,11] : int list
显然,大多数函数都可以按正确的顺序将参数作为对进行,因此直接给出了map和fold函数,而不是将它们包装在匿名函数中。
答案 1 :(得分:1)
这是我尝试使用列表和模式匹配来制作尾递归(有点)版本的算法。它是用OCaml编写的,而不是SML,需要内部列表的升序
let reverse list =
let rec iter list acc :int list = match list with
[] -> acc
| x::xs -> iter xs (x::acc)
in iter list [];;
let listAdd num list =
let rec iter num list acc :int list = match list with
[] -> acc
| x::xs -> iter num xs ((x + num)::acc)
in reverse( iter num list []);;
let listMerge listX listY =
let rec iter listX listY acc : int list = match listX with
[] -> (reverse acc) @ listY
| x :: xs -> match listY with
[] -> (reverse acc ) @ listX
| y :: ys -> match ( compare x y ) with
0 -> iter xs ys ( x::acc )
|(-1) -> iter xs listY ( x::acc )
| 1 -> iter listX ys ( y::acc )
in iter listX listY [];;
let listSums listX listY =
let rec iter listX listY acc = match listX with
[] -> acc
| x :: xs -> iter xs listY ( listMerge acc (listAdd x listY ) )
in iter listX listY [];;
let possibleSums shallowList = match shallowList with
[] -> []
| headList :: lists ->
let rec iter acc lists = match lists with
[] -> acc
| headList :: other -> iter ( listSums acc headList ) other
in iter headList lists;;
此处possibleSums [[1];[1;5];[7];[2;3;4]];;
评估为int list = [11; 12; 13; 15; 16; 17]
所以基本上合乎逻辑的步骤是:
reverse
函数只是在生成累加器后恢复顺序的实用程序 - 尾递归优化的常用概念listAdd
函数,以避免在构建摘要时使用map实用程序listMerge
函数等于set union以将排序列表用作整数集listSums
函数posibleSums
函数,用于将所有集合的完整笛卡尔积的映射求和的最终级别。该算法不仅通过TCO避免了递归中的堆栈溢出,而且还为此计算问题提供了近似最优解。
此解决方案还可以通过添加过早merge sorting并从集合中删除重复元素来进一步改进,因此内部集合顺序现在无关紧要:
let split lst =
let rec iter lst partX partY = match lst with
[] -> partX,partY
| x::xs -> iter xs partY (x::partX)
in iter lst [] [];;
let rec mergeSort lst = match lst with
[] -> []
|[x] -> [x]
| _ -> let partX,partY = split lst in
listMerge (mergeSort partX) (mergeSort partY);;
let possibleSums shallowList = match shallowList with
[] -> []
| headList :: lists ->
let rec iter acc lists = match lists with
[] -> acc
| headList :: other -> iter ( listSums acc (mergeSort headList) ) other
in iter (mergeSort headList) lists;;
您可以通过简单示例测试其效率。让我们定义重复函数来制作重复列表:
let rec repeat elem n = match n with
0 -> []
| _ -> elem :: (repeat elem (n - 1));;
在这种情况下,possibleSums( repeat( repeat 1 30) 30 )
会立即计算出正确的单身答案int list = [30]
。虽然更直接的解决方案(如Jesper的解决方案)将永远这样做。
答案 2 :(得分:-2)
我会尝试使用递归循环来解决它 - 伪代码:
sum = 0;
while (i < arrayOfArrays.length ) {
sumUp(arrayOfArrayElements);
i ++
}
function sumUp() {
while( j < arrayOfArrayElement.length){
sum = sum + arrayOfArrayElement[j].val
j ++
}
}
所以你调用一个函数来汇总一个数组的每个数组元素,并在一个函数内汇总这些值,该函数为该数组数组中的每个元素调用该函数。 LOLZ
- 创建一个带有一组int的函数,并使用for或while循环添加包含的int。
- 遍历主数组并调用每个包含数组元素的函数进行求和,直到没有剩余元素为止,您可以通过使用数组的.length来实现这一点,该数组应该可以在每个脚本/编程中访问语言
醇>