【问题标题】:SML: Create a list from a list of tuples with the second element of each tupleSML:从元组列表中创建一个列表,每个元组的第二个元素
【发布时间】:2019-10-29 16:09:37
【问题描述】:

您好,我是 SML 的新手,我一直在尝试编写一个函数,该函数将一个列表(在我的情况下为列表 prussia)作为参数,该列表具有两个整数和一个字符串的元组,我的函数必须创建列表中出现的所有年份没有重复(列表中每个元组的第二个元素)。我必须这样做创建两个函数(append_if_new 需要一年的列表并将其添加到列表中,它可以工作)并且 year 必须对列表中的所有元组执行此操作,我使用 foldl 尝试过,但我得到了一个 tycon不匹配。

钯。为此,我必须使用函数映射、过滤或折叠,并且我可以将 append_if_new 功能移至 year 函数。我认为错误出现在折叠调用中,我作为参数传递的函数不是我应该传递的函数类型,但我不确定是什么问题。谢谢

    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

【问题讨论】:

    标签: sml


    【解决方案1】:

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

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

    您可以使用map 创建一个包含重复项的列表,然后过滤重复项:

    fun year_of (_, year, _) = year
    fun member (y, xs) = List.exists (fn x => y = x) xs
    fun nub [] = []
      | nub (x::xs) = if member (x, xs)
                      then nub xs
                      else x :: nub xs
    
    fun years records = nub (map year_of records)
    

    这里nub 具有O(n²) 的渐近运行时间复杂度,这是不好且不必要的。您也可以直接折叠列表,这样您就不会插入重复的开头:

    fun member (y, xs) = List.exists (fn x => y = x) xs
    
    fun years records =
        let
          fun insert ((_, year, _), years) =
              if member (year, years)
              then years
              else year :: years
        in
          foldr insert [] records
        end
    

    但是渐近运行时间是一样的,读起来稍微晦涩一些。如果您想以有效的方式过滤重复项,则必须使用更有效的数据结构来管理重复项,例如基于树的集合或类似的。在 Haskell 中,这就是 nubnubOrd 之间的区别。

    【讨论】:

      【解决方案2】:

      有两个问题:

      • 您的折叠初始值错误 - 由于结果应该是一个列表,所以初始值也必须是一个列表;
      • 您的 append_if_new 函数的参数太少,错误太多。

      如果你替换 let-bound 定义,append_if_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)]
      

      由于条件始终为假 - 您永远不会在空列表中找到任何内容 - 而[] @ 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;
      

      测试:

      - add_if_new ((1,2,3), []);
      val it = [2] : int list
      - add_if_new ((1,2,3), [3]);
      val it = [2,3] : int list
      - add_if_new ((1,2,3), [2]);
      val it = [2] : int list
      

      和:

      fun years (lista: (int*int*string) list): int list =
          List.foldl add_if_new [] lista
      

      测试:

      - years [(12,0, "G"), (12,1,"G"), (12,0,"G")];
      val it = [1,0] : int list
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多