2013-06-28 55 views
1

我对函数式编程完全陌生;这是SML的作业分配。将常用项目列表转换为有序对列表

我有一个整数列表,我试图得到一个有序对的列表,其中第二个条目是第一个条目出现在初始列表中的次数。

例如:

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

我不希望别人来实现此,而是给我的什么排序高阶函数我要寻找的想法,和/或指针在正确的方向。同样,对于函数式编程来说也是全新的,对于SML语言来说更是新的东西。

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

回答

3

因此,为此,您可能需要使用折叠,如foldl

在一般情况下,决定是否使用map或折叠(下面我带折叠意味着要么foldlfoldr),您可以用拇指以下规则时:

如果你想从列表中具有完全相同与列表中相同数量的元素,您可能需要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 | 

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

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

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

除了使用折叠,这里是另一个提示:由于[(2,1),(3,2),(5,1)]是最终结果,折叠使用的累加函数的返回值可能具有此类型; (int * int) list。然后,降低了问题

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

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