List f#列表的交集
函数mem将list和var X作为参数,检查list是否包含值X,如果包含值X,则返回true,如果不包含值X,则返回falseList f#列表的交集,list,f#,intersection,List,F#,Intersection,函数mem将list和var X作为参数,检查list是否包含值X,如果包含值X,则返回true,如果不包含值X,则返回false let rec mem list x = match list with | [] -> false | head :: tail -> if x = list.Head then true
let rec mem list x = match list with
| [] -> false
| head :: tail ->
if x = list.Head
then true
else mem list.Tail x
我对F#很陌生,现在的问题是我不知道如何在(将值添加到列表中)中构造一个列表,然后将值添加到列表中。我还没有测试代码,因为我需要先完成这一步,以免出错,所以我不能100%确定它是如何工作的
我正在尝试相交2个列表,我知道它确实存在此“Set.intersect list1 list2”的函数。缩进在这里也有点奇怪,因为我不想说太多的行,但无论如何你都会理解的。修复代码的最直接方法是编写如下代码 在
mem
函数中,我刚刚修复了缩进,并将其更改为使用模式匹配中获得的head
和tail
,而不是通过list.head
和list.tail
访问它们(因为这样做更惯用、更安全):
在intersection
中,诀窍是当head
是出现在两个列表中的元素时,使用head::rest
构建一个结果列表(而rest
是通过递归地将交集应用于尾部而得到的列表)。您也不需要在list2
上进行匹配,因为mem
可以很好地处理空列表:
let rec mem list x =
match list with
| [] -> false
| head :: tail ->
if x = head then true else mem tail x
这不是非常有效(假设n是list1
的长度,m是list2
的长度,您可能需要多达m*n个步骤),但这可能不是重点。另外,intersection
不是尾部递归的,因此它不能处理大型列表,但这是另一个更高级的函数式编程主题
最后,代码还将多次返回可能包含单个元素的列表-但我想这对您来说没什么问题(例如,
交叉点[1;1;1][1]
返回[1;1;1]
,但如果翻转参数,您只会得到[1]
)为了做到这一点,您需要跟踪正在建立的列表。最好的方法是定义一个helper函数,该函数将生成的列表作为参数,并将其包含在递归调用中
let rec intersection list1 list2 =
match list1 with
| head :: tail ->
let rest = intersection tail list2
if mem list2 head then head::rest
else rest
| [] -> []
另一个评论是,在空列表上失败是一种不好的做法。只需将空列表视为没有元素的列表,因此不可能存在交集
let intersection list1 list2 =
let rec inner list1 list2 builtList =
match list1 with
| head :: tail ->
match list2 with
| head :: tail ->
if mem list2 list1.Head = true then
inner tail list2 (list1.Head :: builtList)
else
inner tail list2 builtList
| [] -> failwith "Second list is empty"
| [] -> failwith "First list is empty"
inner list1 list2 []
此版本可以工作,但最终将返回一个列表,该列表中的元素与它们在list1
中的显示顺序相反。为了解决这个问题,我们可以使用回调以正确的顺序建立列表
let intersection list1 list2 =
let rec inner list1 list2 builtList =
match list1 with
| head :: tail ->
if mem list2 list1.Head = true then
inner tail list2 (list1.Head :: builtList)
else
inner tail list2 builtList
| [] -> builtList
inner list1 list2 []
我喜欢使用集合运算符
你可以使用Set.intersect(Set.ofList list1)(Set.ofList list2)|>Set.toList我迟到了1000年,但如果有人对这个问题感到不快,第一条评论中的答案对我来说不起作用。但是,这可能总是我的错,我对F#相当陌生。我提出了以下似乎很有效的方法。 任何关于改进的意见都是欢迎的,因为我的代码可能有点愚蠢 在这一点上,我不想使用内置操作符,因为我是为一个类这样做的 ps1。我不想使用
如果
,我的教授更喜欢匹配
(idk为什么)
let intersection list1 list2 =
let rec inner list1 list2 builtList =
match list1 with
| head :: tail ->
if mem list2 list1.Head = true then
inner tail list2 (list1.Head :: builtList)
else
inner tail list2 builtList
| [] -> builtList
inner list1 list2 []
let intersection list1 list2 =
let rec inner list1 list2 builder =
match list1 with
| head :: tail ->
if mem list2 list1.Head = true then
inner tail list2 (fun next -> list1.Head :: next)
else
inner tail list2 builder
| [] -> (builder [])
inner list1 list2 (fun x -> x)
let rec intersect =
function
| ([],[]) -> []
| ([],_) -> []
| (_,[]) -> []
| (x::xtail,y::ytail) -> match x=y with
| true -> x::intersect(xtail,ytail)
| false -> intersect(xtail,y::ytail)