将包含常用项的列表转换为有序对列表

时间:2013-06-28 19:17:18

标签: functional-programming sml smlnj

我对函数式编程完全陌生;这是SML的家庭作业。

我有一个整数列表,我正在尝试获取有序对的列表,其中该对的第二个条目是第一个条目出现在初始列表中的次数。

例如:

[2,3,3,5] => [(2,1),(3,2),(5,1)]

我不希望有人实现这个,而是让我知道我正在寻找什么类高阶函数,和/或指向正确方向的指针。同样,对于函数式编程来说还是全新的,甚至是SML语言的新功能。

我最初的想法是我想使用map,但我无法弄清楚如何跟踪或合并类似的项目。我只是成功地将每个项目变为有序对,第二个条目等于1 ......完全没用。

2 个答案:

答案 0 :(得分:3)

所以,为此你可能想要使用折叠,比如foldl

一般情况下,在决定是使用map还是折叠(此处我将折叠表示为foldlfoldr)时,您可以使用以下经验法则:< / p>

如果您想要的列表与您输入的列表具有完全相同的元素数,则可能需要map。否则,你需要折叠。

推理如下:对于列表中的每个元素,map在输出中生成转换后的元素。另一方面,折叠更为通用,可以做任何你想做的事情。 (而且你确实可以使用折叠实现map。这并不意味着你当然不需要让事情变得不必要复杂。)

为了完整起见,让我简单解释折叠是如何工作的。折叠遍历列表(左侧为foldl,右侧为foldr,因此为名称),一次在累加器中构建一个元素。

让我们在一个例子中看到它:

foldl (fn (e, a) => e + a) 0 [5, 3, 7, 10]

这里e是我们当前正在使用的元素,a是累加器变量(即当前结果)。我们从a = 0开始,因为我们将0指定为起始值。

|  e | a  | new a
-------------------------
| 5  | 0  |  5 +  0 = 5
| 3  | 5  |  3 +  5 = 8
| 7  | 8  |  7 +  8 = 15
| 10 | 15 | 10 + 15 = 25
|    | 25 | 

这为我们提供了a的最终25,我们看到该函数总结了列表中的元素。请注意,在任何迭代中,a的值是到目前为止列表中元素的总和,以及我们每个步骤如何扩展此列表以包含一个元素。

这是我建议的解决此问题的方法。

  • 考虑a的基本值应该是什么。 (与将[]作为输入的结果相同。)
  • 然后考虑如何从较小的列表中获取结果,并将其扩展为包含另一个元素。

答案 1 :(得分:0)

除了使用折叠之外,还有另一个提示:由于[(2,1),(3,2),(5,1)]是最终结果,因此折叠使用的累积函数的返回值可能具有此类型; (int * int) list。然后,您已将问题缩小为

foldl (fn (elem, acc) => ...) [] xs

其中f应插入elem,例如5accum,例如[(2,1),(3,2)]f可以被认为是插入函数,或者等效地,调用这样的插入函数,只要它产生类似[(2,1),(3,2),(5,1)]的东西(即,查看已经找到的元素,如果找到则增加它,或者插入它)如果没有找到,则计数为1。