如何跨过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]
。
在这两个答案之间,应该可以非常简单地组合出您的问题的解决方案,并希望了解它的工作原理。
我有一个列表和一个元组 (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]
。
在这两个答案之间,应该可以非常简单地组合出您的问题的解决方案,并希望了解它的工作原理。