【问题标题】:How do I pair the elements in the first list with all the elements in a second list in SML?如何将第一个列表中的元素与 SML 中第二个列表中的所有元素配对?
【发布时间】:2019-03-07 03:03:24
【问题描述】:

问题陈述:编写一个函数对,它接受两个整数列表并生成一个对列表,其中每个对是每个列表中每个元素的组合。

例如,pair ([1,2], [3,4,5]) 应该返回

[(1,3), (1,4), (1,5), (2,3), (2,4), (2,5)].

到目前为止我的工作:

-fun pair(a:int list, b:int list) = if null a then nil else if null b then nil else (hd a, hd b)::pair(a, tl b)@pair(tl a, b);

val pair = fn : int list * int list -> (int * int) list

-pair([1,2],[3,4,5]);

val it = [(1,3),(1,4),(1,5),(2,5),(2,4),(2,5),(2,3),(2,4),(2,5)]

我试图追踪函数以找出为什么 (2,5)、(2,4)、(2,5) 会出现,但我仍然看不清楚。

这似乎很简单,但我似乎无法解决最后的问题。一些帮助查明为什么在中间添加这些元素会有所帮助。

谢谢。
彼得

【问题讨论】:

    标签: list functional-programming sml smlnj


    【解决方案1】:

    主要问题是您在两个列表上进行递归。

    如果你看看你的例子,

    pair ([1,2], [3,4,5]) -> [(1,3), (1,4), (1,5), (2,3), (2,4), (2,5)]
    

    你会看到它有两个子列表,

    [(1,3), (1,4), (1,5)]
    [(2,3), (2,4), (2,5)]
    

    其中第一个由[1,2]的第一个元素和[3,4,5]的每个元素组成的对组成,第二个是[1,2]的第二个元素,也与[3,4,5]的每个元素配对。
    请注意,每个子列表包含所有[3,4,5],但只有[1,2] 的一个元素 - 第一个与pair ([1], [3,4,5]) 相同,第二个是pair ([2], [3,4,5]) - 所以你只需要递归第一个列表。

    您可以像这样创建这样的列表:

    • 如果任何输入列表为空,则结果为空。
    • 否则:
      1. 将a 的第一个元素与列表中b 的每个元素配对(提示:考虑map。)
      2. 递归地从a 的尾部和b 的尾部组成对。
      3. 结合 1 和 2 的结果。

    使用模式匹配:

    fun pair ([], _) = []
      | pair (_, []) = []
      | pair (x::xs, ys) = <something involving x and ys, suitably combined with 'pairs (xs, ys)'> 
    

    如果您将步骤 1 编写为单独的函数,可能会有所帮助。

    【讨论】:

    • 事实上,我确实将第一步编写为问题集中另一个问题的单独函数。我忽略了一个事实,即我可以使用我的“附加”函数(将一个 int 连接到一个 int 列表中的所有元素)来实现对。我们在此示例中不使用模式匹配,但您的回答中显示了一般流程,谢谢。
    【解决方案2】:

    由于这是一个练习,我不会向你展示问题陈述的答案。

    您尝试生成的内容称为两个列表的笛卡尔积。

    您当前的方法(格式更好),

    fun pair (a, b) =
      if null a then nil else
      if null b then nil else
      (hd a, hd b) :: pair (a, tl b) @ pair (tl a, b);
    

    会产生重复的结果,因为您在pair (a, tl b) 中遗漏了hd b,并且在pair (b, tl a) 中遗漏了hd a,但是在第二次迭代中,例如pair (a, tl b),a 的第一个元素对tl b 的每个剩余元素再次处理。

    您可以通过处理每个元素一次来避免这种重复工作。我建议您查看函数map 和concat。一般方法是这样的:对于a 的每个元素x,为b 的每个元素y 生成(x,y)。 “对于每个元素”是 map。和

    map (fn x => ...something with (x,y)...) a
    

    产生一个列表的结果,就像你想要的那样。但是,如果您重复 map (fn y =&gt; ...) b 与 ...something with (x,y)... 部分相同的方法,您会遇到concat 可以帮助您的不便惊喜。

    您可以不使用map 和concat 而是使用手动递归来解决此练习,但是您可能必须将工作拆分为两个函数,因为您需要一个折叠在x 上的函数a,对于每个 x,将 b 折叠一次。函数map 采用了这两个函数共有的递归部分,并让您只编写它们没有共同点的东西。

    【讨论】:

      猜你喜欢
      • 2016-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-25
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多