如何跨过sml中的列表?

how to step over a list in sml?

我有一个列表和一个元组 (start,end,interval) 我正在尝试遍历列表和 return 列表中的元素,从头到尾使用间隔步骤。 例如:

cutt [1,2,3,4,77,8,7] (1,5,2);
val it = [2,4,8] : int list;

问题是我不能使用递归, 我正在考虑使用 foldl,但问题是如何跳过我不想使用的元素 list.nth? 我会appriciate小提示!谢谢

一种正确跳过你不想要的元素的解决方案 结果列表,就是给你的函数加一个参数,用来折叠 你的清单。这个参数的意思基本上就是“有多少物品 你还是想跳过。

例如,下面是一个使用 List.foldl 的解决方案。这 用于折叠列表项的函数有两个参数: 第一个是上面讨论的,第二个是 正在构建结果列表。

fun cutt lst (idx_start, idx_end, interval) = let
    val (_, result) =
        List.foldl
            (fn (x, (0, result)) =>
                (* no more item to skip => add x to the resulting list *)
                (interval - 1, x :: result)
            |   (_, (n, result)) =>
                (* there are still items to skip *)
                (n - 1, result))
            (idx_start, [])  (* initially we skip idx_start items *)
            lst
in
    (* items are prepended in the resulting list in reverse order =>
    reverse the list *)
    List.rev result
end;
                         
val x = cutt [1, 2, 3, 4, 77, 8, 7] (1, 5, 2);

当然函数需要适配,因为它没有照顾 idx_end 参数。

听起来你需要两个函数。第一步是在索引之间检索列表的一部分。这听起来与 a solution posted very recently.

可疑相关
fun slice'(lst, start, stop) =
 let
   val (_, lst') = foldl 
     (fn (v, (idx, acc)) => 
        if idx >= start andalso idx <= stop then 
          (idx + 1, v::acc) 
        else 
          (idx + 1, acc)) 
     (0, []) 
     lst
 in
   List.rev(lst')
 end;

如果我们尝试 slice'([1,2,3,4,77,8,7], 1, 5),结果是 [2, 3, 4, 77, 8]

要达到 [2, 4, 8],我们只需要删除每个第二个元素。这可以根据简单的递归定义如下。

fun dropn(n, lst) =
  let 
    fun dropn'(_, _, []) = []
      | dropn'(n, c, x::xs) = 
        if c = n then x :: dropn'(n, 1, xs)
        else dropn'(n, c + 1, xs)
  in
    dropn'(n, n, lst)
  end

但是显然你不能使用递归,所以让我们使用折叠。

fun drop(n, lst) =
  List.foldl 
    (fn (x, (acc, i)) => if i = n then (x :: acc, 1) else (acc, i + 1))
    ([], n)
    lst

现在,如果我们尝试 drop(2, [1,2,3,4,77,8,7]),我们会得到 ([7, 77, 3, 1], 1),其中 确实 包含我们想要的列表,但也包含计数器,并且列表是向后的,因为我们建立它的方式。让我们在逐步完成这个简单示例时考虑一下累加器是如何工作的。

Initial state: 
  lst: [1,2,3,4,77,8,7]
  acc: []; i: 2

First iteration:
  x: 1
  acc: [1]; i: 2

Second Iteration:
  x: 2
  acc: 1 :: [];  i: 1

Third iteration: 
  x: 3
  acc: 3 :: 1 :: []; i: 2

Fourth iteration:
  x: 4
  acc: 3 :: 1 :: []; i: 1

Fifth iteration:
  x: 77
  acc: 77 :: 3 :: 1 :: []; i: 2

Sixth iteration:
  x: 8
  acc: 77 :: 3 :: 1 :: []; i: 1

Seventh iteration:
  x: 7
  acc: 7 :: 77 :: 3 :: 1 :: []; i: 2

Final step:
  remaining list: []
  acc: 7 :: 77 :: 3 :: 1 :: [] or [7, 77, 3, 1]; i: 1

不过,提取和反转该列表很容易。

fun drop(n, lst) =
  let
    val (lst', _) = List.foldl 
      (fn (x, (acc, i)) => if i = n then (x :: acc, 1) else (acc, i + 1))
      ([], n)
      lst
  in
    List.rev lst'
  end

所以现在 drop(2, [1,2,3,4,77,8,7]) 的计算结果为 [1, 3, 77, 7]

在这两个答案之间,应该可以非常简单地组合出您的问题的解决方案,并希望了解它的工作原理。