每月练习次数(SML中多个列表的迭代)

每月练习次数(SML中多个列表的迭代),sml,Sml,我在SML中有两个列表,比如列表A[(A,b,c),(d,e,f)]和列表b[b,e]。我想计算B中每一项与A中每三元组的第二个元素相匹配的出现次数。输出应该是2。因为b和e每一个都在A中出现一次 到目前为止,这是我的代码,但当我在B中从一个元素移动到另一个元素时,我的计数器总是设置为0。我知道在Java中,这只是一个简单的双for循环 fun number_in_months (d : (int * int * int ) list, m : (int) list) = if nul

我在SML中有两个列表,比如列表A
[(A,b,c),(d,e,f)]
和列表b
[b,e]
。我想计算B中每一项与A中每三元组的第二个元素相匹配的出现次数。输出应该是2。因为
b
e
每一个都在A中出现一次

到目前为止,这是我的代码,但当我在B中从一个元素移动到另一个元素时,我的计数器总是设置为0。我知道在Java中,这只是一个简单的双for循环

fun number_in_months (d : (int * int * int ) list, m : (int) list) = 
    if null m then 0 
    else if null d then number_in_months(d, tl m)
    else if (#2(hd d)) = (hd m) then 1 + number_in_months (tl d, m)
    else number_in_months(tl d, m)

代码没有在递归调用之间累积值。可能还有其他逻辑错误

使用递归和函数累积值是一种常见的模式,您可以了解更多。它的本质是使用
head
tail
解构列表,直到列表为空,并在每次调用时累积一些值。下面的
sum
函数就是一个简单的例子。当在
列表A
中找到
b
e
时,这可以适用于您的示例,以累积
acc

fun sum(numbers: (int) list) =
  let fun sumR(numbers: (int) list, acc: int) =
    if null numbers
    then acc
    else
      sumR(tl numbers, hd numbers + acc)
  in
    sumR(numbers, 0)
  end
[1,2,3]
上运行会给出:

val sum = fn : int list -> int
- sum([1,2,3]);
val it = 6 : int

注意,我有意含糊其辞,因为这是一个关于编程语言课程的Coursera作业的问题。

正如您所提到的,在任何命令式编程语言中,这都是一个嵌套/双循环。您实际上缺少的是第二个循环

“内部”循环遍历
d
的所有元素,完成后,“外部”循环尝试弹出
m
的顶部元素并从头开始,如代码的这一行所示:

else if null d then number_in_months(d, tl m)
但是,正如您所看到的,您刚刚测试了列表
d
为空,并将此列表(完全相同的列表)提供给
m
尾部的递归调用,然后每个后续调用都将属于相同的情况,直到
m
也为空并且返回0为止

因此,您缺少的是“保留一份”原始输入列表
m
。这可以通过多种方式完成,但内部(helper)函数是最常用的函数,它甚至“看起来”像一个嵌套循环

fun number_in_months (d, m) =
    let
      fun nim' ([], y::ys) = nim (d, ys)                 (* 1 *)
        | nim' (_, []) = 0                               (* 2 *)
        | nim' ((_, x2, _) :: xs, yss as (y::ys)) = ...  (* 3 *)
    in
      nim'(d, m)
    end
使用模式匹配上述代码会变得更简单,更不容易出错。在案例1中,“内部”循环已通过
d
中的所有元素,因此使用外部函数的
d
进行递归调用,该调用在任何时候都不会更改。在案例2中,“外部”循环已经遍历了
m
的所有元素,我们返回0(加法的中性元素)。在案例3中,我们进行实际工作。这里使用了模式匹配,这样我们就不需要强制执行参数的类型,也不需要提取三元组的第二个元素,我们已经在变量
x2
中找到了它。所有需要做的就是进行计算并使用
xs
yss
进行递归调用


这样做时,内部(helper)函数使用原始输入列表的“副本”
d
,并逐步遍历其元素(可能会对其进行修改),但我们始终获得原始输入列表的引用,我们可以在需要时使用它。

如果我在[(1,2,3)(2,2,3)(4,2,3)],[2,4]上运行代码,谢谢您的回答我得到了答案6,这是中间2的总和。因此,它的累加问题是它应该继续下去,并且在第一个列表的中间元素中检查4,如果发现4,则应该将6更新到7。对于<代码> NothByIn个月< /代码>输入<代码> [1(2,3),(2,2,3),(4,2,3)],[2,4]的答案。应该是3,因为每个
日期都有
2
,因为月份和
2
月份列表中
是的,你是对的,应该是3而不是6,这是我的错误。你真的不想使用模式匹配而不是测试
null
的空列表。这样,您也不需要显式地获取列表的开头和结尾,因为您已经将它们模式匹配为例如(x::xs)和(y::ys)。感谢您的解释,您指出的错误非常重要,我终于得到了我想要的。