问题陈述:编写一个函数对,该函数对包含两个整数列表并生成一个成对的列表,其中每个对都是每个列表中每个元素的组合。
例如,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)
,但我仍然看不到它的踪影。
这似乎很简单,但是我似乎无法解决最后的问题。指出为什么在中间添加这些元素的一些帮助会有所帮助。
谢谢。
彼得
答案 0 :(得分:0)
由于这是一种练习,因此我不会向您展示问题陈述的答案。
您要生成的东西称为两个列表的笛卡尔积。
您当前的方法(格式更好)
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);
会产生重复的结果,因为您在hd b
中遗漏了pair (a, tl b)
而在hd a
中遗漏了pair (b, tl a)
,但是在第二次迭代中,例如pair (a, tl b)
,将a
的每个剩余元素再次处理tl b
的第一个元素。
您可以通过一次处理每个元素来避免这种重复工作。我建议您查看函数map
和concat
。通用方法是这样的:对于x
的每个元素a
,为(x,y)
的每个元素y
生成b
。 “对于每个元素”为map
。还有
map (fn x => ...something with (x,y)...) a
生成结果的列表,就像您想要的那样。但是,如果您重复使用与map (fn y => ...) b
部分相同的...something with (x,y)...
方法,您会惊讶地发现concat
可以为您提供帮助。
您可以在不使用map
和concat
的情况下解决此问题,而不必使用手动递归,但是您可能需要将工作分为两个功能,因为您需要一个功能可以折叠x
中的a
,并且对于每个x
,都在b
上折叠一次。函数map
包含了这两个函数共有的递归部分,并且仅允许您编写它们没有的东西。
答案 1 :(得分:0)
主要问题是您要遍历两个列表。
如果您查看示例,
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]
的第二个元素也与{的每个元素配对{1}}。
请注意,每个子列表包含所有[3,4,5]
,但仅包含[3,4,5]
的一个元素-第一个与[1,2]
相同,第二个为pair ([1], [3,4,5])
-因此,您只需要递归第一个列表。
您可以创建这样的列表:
pair ([2], [3,4,5])
的第一个元素,并将其与列表中a
的每个元素配对(提示:考虑b
。)map
的尾部和所有a
的尾部进行配对。具有模式匹配:
b
如果将第1步作为单独的函数编写,则可能会有所帮助。