【问题标题】:Alternating elements from 2 lists SML来自 2 个列表 SML 的交替元素
【发布时间】:2023-10-26 03:35:01
【问题描述】:

我的 SML 代码在交替使用 2 个列表元素时遇到了困难。我必须创建一个最终列表,该列表将采用 2 个相同大小的列表并交替它们的元素。一个例子是 alternate([1,3,5],[2,4,6]) = [1,2,3,4,5,6] 我不确定代码哪里出错了。任何帮助将不胜感激。这是我目前拥有的代码

fun alternate2([],y) = []
    | alternate2(a::x,y) = 
    if length listx = length listy then
        if countListx = countListy then (List.nth(listx, countListx)::alternate2(x,y); count(countListx))
        else if countListx <> length listx - 1 then 
            if countListy < countListx then (alternate2(x, a::y); count(countListy))
            else alternate2(x,y)
        else alternate2(x,y)
    else alternate2(x,y);

【问题讨论】:

    标签: sml


    【解决方案1】:

    您可以完全通过模式匹配和递归来完成此操作,而无需使用 lengthif-then-else=。由于这个练习太小了,我发现不给出答案就很难给出文字提示,所以我将尝试以类似的方式解决类似的练习:

    给定一个函数f : 'a * 'b -&gt; 'c 和两个列表xs : 'a listys : 'b list,我可以通过将函数f 应用于每对(x, y) 来创建结果'z list,其中每个x 来自@ 987654331@ 和每个y 来自ys。如果一个列表比另一个长,我将丢弃多余的元素。

    fun zipWith (f, x::xs, y::ys) = f (x, y) :: zipWith (f, xs, ys)
      | zipWith (_, [], []) = [] (* end of both lists *)
      | zipWith (_, xs, []) = [] (* xs is longer, discard it *)
      | zipWIth (_, [], ys) = [] (* ys is longer, discard it *)
    

    由于最后三种情况的反应都是一样的,我也可以这样写:

    fun zipWith (f, x::xs, y::ys) = f (x, y) :: zipWith (f, xs, ys)
      | zipWith (_, _, _) = [] (* either one or both lists are empty *)
    

    你的函数alternate2 的行为非常相似,除了每一步的计算不是f (x, y),因为你自然没有f。此外,在 alternate2 的情况下,每对 xy 不应产生单个元素,而是连续产生两个元素。

    - zipWith (op+, [1,2,3], [10,20,30]);
    > val it = [11, 22, 33] : int list
    

    【讨论】:

      【解决方案2】:

      有几种方法可以做到这一点,但我会建议一种符合你的函数类型 ('a list * 'a list -&gt; 'a list) 并且还严格执行两个输入列表必须具有相同大小的约束的方法.

      fun interleave ([],[]) = []
        | interleave (x::xs,y::ys) = x :: y :: interleave (xs,ys);
      

      此功能通过模式匹配工作。在最简单的情况下,它需要两个空列表并返回一个空列表。否则,它应该期望有两个列表,每个列表中至少包含一个项目。

      如果传递了两个不同长度的列表,则会引发匹配异常,因为 ([], y::ys)(x::xs, []) 不匹配任何指定的模式。

      这意味着编译器可能会产生警告 (warning: Matches are not exhaustive.),但这是设计使然。

      也可以创建一个显式异常,导致类似:

      exception DifferentLengthsException;
      fun interleave ([],[]) = []
        | interleave (x::xs,y::ys) = x :: y :: interleave (xs,ys)
        | interleave (xs,ys) = raise DifferentLengthsException;
      

      如果将两个不同长度的列表传递给其中任何一个函数,则会引发异常(以下是示例堆栈跟踪)。

      val x = interleave ([1,3,5,7],[2,4,6]);
      val x = 1 :: 2 :: interleave ([3,5,7], [4,6]);
      val x = 1 :: 2 :: 3 :: 4 :: interleave ([5,7], [6]);
      val x = 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: interleave ([7], []);
      Exception- Match raised
      

      【讨论】:

      • 处理不匹配长度的替代方法,除了一个例外:丢弃剩余的元素,或将剩余的末端添加为列表的尾部。哪个更好取决于应用程序,但避免异常或错误状态在任何一种情况下都是理想的。