SML:从具有每个元组的第二个元素的元组列表创建一个列表

SML:从具有每个元组的第二个元素的元组列表创建一个列表,sml,Sml,您好,我是SML的新手,我一直在尝试编写一个函数,该函数作为参数获取一个列表(在我的例子中是list prussia),该列表包含两个int和一个字符串的元组,我的函数必须创建一个列表,其中包含列表中出现的所有年份,不重复(列表中每个元组的第二个元素)。我必须创建两个函数(append_如果_new需要列表中的一年时间并将其添加到列表中,它就会工作),而year必须为列表中的所有元组执行此操作,我尝试使用foldl,但我得到了tycon不匹配 警察局。要做到这一点,我必须使用功能映射、过滤器或折

您好,我是SML的新手,我一直在尝试编写一个函数,该函数作为参数获取一个列表(在我的例子中是list prussia),该列表包含两个int和一个字符串的元组,我的函数必须创建一个列表,其中包含列表中出现的所有年份,不重复(列表中每个元组的第二个元素)。我必须创建两个函数(append_如果_new需要列表中的一年时间并将其添加到列表中,它就会工作),而year必须为列表中的所有元组执行此操作,我尝试使用foldl,但我得到了tycon不匹配

警察局。要做到这一点,我必须使用功能映射、过滤器或折叠,并且我可以将“如果”新功能添加到“年份”功能中。我认为错误在于fold调用中,我作为参数传递的函数不是我应该传递的函数类型,但我不确定问题出在哪里。谢谢

    val prussia =
  [(0,1875,"G"),(2,1876,"G"),(2,1877,"G"),(1,1878,"G"),(0,1879,"G"),
   (0,1880,"G"),(1,1881,"G"),(1,1882,"G"),(0,1883,"G"),(3,1884,"G"),
   (0,1885,"G"),(2,1886,"G"),...] : (int * int * string) list

fun append_if_new (lista:(int*int*string)list): int list =
    let 
        val lista2 = []
        val x = hd lista
        val z = #2x
    in
        if (List.exists (fn y => y = z) lista2) 
        then lista2
        else lista2@[z]
    end

fun years (lista:(int*int*string)list): int list =
    List.foldl append_if_new 0 lista
创建一个包含列表中所有年份的列表,不重复

(列表中每个元组的第二个元素)

您可以使用
map
创建重复列表,然后过滤重复项:

fun year of(u,year,u)=年
有趣的成员(y,xs)=List.exists(fn x=>y=x)xs
乐趣点[]=[]
|nub(x::xs)=if成员(x,xs)
然后是nubxs
else x::nub xs
乐趣年记录=nub(地图年记录)
这里,
nub
的渐进运行时间复杂性为O(n²),这是不好的和不必要的。您也可以直接向前折叠列表,这样您就永远不会插入重复项:

fun成员(y,xs)=List.exists(fn x=>y=x)xs
欢乐岁月唱片=
让
趣味插页((u,年,u,年)=
if成员(年,年)
然后几年
其他年份::年
在里面
foldr insert[]记录
结束
但是渐近运行时间是相同的,并且它稍微更难以理解。如果要以有效的方式过滤重复项,则必须使用更高效的数据结构来管理重复项,如基于树的集合或类似集合。在Haskell中,这就是和之间的区别

创建一个包含列表中所有年份的列表,不重复

(列表中每个元组的第二个元素)

您可以使用
map
创建重复列表,然后过滤重复项:

fun year of(u,year,u)=年
有趣的成员(y,xs)=List.exists(fn x=>y=x)xs
乐趣点[]=[]
|nub(x::xs)=if成员(x,xs)
然后是nubxs
else x::nub xs
乐趣年记录=nub(地图年记录)
这里,
nub
的渐进运行时间复杂性为O(n²),这是不好的和不必要的。您也可以直接向前折叠列表,这样您就永远不会插入重复项:

fun成员(y,xs)=List.exists(fn x=>y=x)xs
欢乐岁月唱片=
让
趣味插页((u,年,u,年)=
if成员(年,年)
然后几年
其他年份::年
在里面
foldr insert[]记录
结束

但是渐近运行时间是相同的,并且它稍微更难以理解。如果要以有效的方式过滤重复项,则必须使用更高效的数据结构来管理重复项,如基于树的集合或类似集合。在Haskell中,这就是和之间的区别。

有两个问题:

  • 折叠的初始值是错误的-因为结果应该是一个列表,初始值也必须是一个列表
  • 您的
    append\if\u new
    函数的参数太少,bug太多
如果替换let绑定定义,
append\u If\u new
变为

fun append_if_new (lista:(int*int*string)list): int list =
    if List.exists (fn y => y = #2 (hd lista)) [] 
    then []
    else []@[#2 (hd lista)]
由于条件始终为false-您将永远无法在空列表中找到任何内容-并且
[]@xs
相当于
[xs]
,因此我们可以将其进一步简化为

fun append_if_new (lista:(int*int*string)list): int list =
    [#2 (hd lista)]
这显然是不正确的-此函数将始终生成一个列表,其唯一元素是第一个条目的年份

例如:

- append_if_new prussia;
val it = [1875] : int list
传递给
foldl
的函数接受两件事——“当前元素”和“到目前为止的结果”——并将它们组合起来生成“下一个”结果。
像这样:

fun add_if_new ((_,y,_), so_far) = if List.exists (fn z => y = z) so_far 
                                   then so_far 
                                   else y :: so_far;
测试:

以及:

测试:


有两个问题:

  • 折叠的初始值是错误的-因为结果应该是一个列表,初始值也必须是一个列表
  • 您的
    append\if\u new
    函数的参数太少,bug太多
如果替换let绑定定义,
append\u If\u new
变为

fun append_if_new (lista:(int*int*string)list): int list =
    if List.exists (fn y => y = #2 (hd lista)) [] 
    then []
    else []@[#2 (hd lista)]
由于条件始终为false-您将永远无法在空列表中找到任何内容-并且
[]@xs
相当于
[xs]
,因此我们可以将其进一步简化为

fun append_if_new (lista:(int*int*string)list): int list =
    [#2 (hd lista)]
这显然是不正确的-此函数将始终生成一个列表,其唯一元素是第一个条目的年份

例如:

- append_if_new prussia;
val it = [1875] : int list
传递给
foldl
的函数接受两件事——“当前元素”和“到目前为止的结果”——并将它们组合起来生成“下一个”结果。
像这样:

fun add_if_new ((_,y,_), so_far) = if List.exists (fn z => y = z) so_far 
                                   then so_far 
                                   else y :: so_far;
测试:

以及:

测试: