let rec mem list x = match list with
| [] -> false
| head :: tail ->
if x = list.Head
then true
else mem list.Tail x
函数mem将列表和var X作为参数,并检查列表是否包含值X,如果匹配则返回true,如果是,则返回false。
let rec intersection list1 list2 = match list1 with
| head :: tail -> match list2 with
| head :: tail -> if mem list2 list1.Head = true
then (*add the value to a list*) else intersection list1.Tail list2
| [] -> failwith "Second list is empty"
| [] -> failwith "First list is empty"
我对F#很新,我现在遇到的问题是我不知道如何在(将值添加到列表)中构建列表然后将值添加到它。我还没有测试过代码,因为我需要先完成这一步,以免出错,所以我不能100%确定它是如何工作的。
我正在尝试交叉2个列表,我知道它确实存在这个“Set.Intersect list1 list2”的函数。缩进在这里有点奇怪,因为我不想长行,但你可能会理解。
答案 0 :(得分:11)
我喜欢使用集合运算符http://msdn.microsoft.com/en-us/library/ee353629.aspx
您可以使用Set.intersect (Set.ofList list1) (Set.ofList list2) |> Set.toList
答案 1 :(得分:7)
修复代码的最直接方法是编写类似下面代码的内容。
在mem
函数中,我只修复了缩进并将其更改为使用从模式匹配中获得的head
和tail
,而不是通过list.Head
和{{}获取它们{1}}(因为这样做更惯用,更安全):
list.Tail
在let rec mem list x =
match list with
| [] -> false
| head :: tail ->
if x = head then true else mem tail x
中,当intersection
是出现在两个列表中的元素时,诀窍是使用head::rest
来构建结果列表(并且head
是列表你可以通过递归方式将尾部应用于尾部)。您也不需要在rest
上匹配,因为list2
处理空列表很好:
mem
这不是超级有效的(假设 n 是let rec intersection list1 list2 =
match list1 with
| head :: tail ->
let rest = intersection tail list2
if mem list2 head then head::rest
else rest
| [] -> []
的长度而 m 是list1
的长度,您可能需要到 m * n 步骤),但这可能不是重点。此外,list2
不是尾递归的,因此它不适用于大型列表,但这是另一个 - 更高级的函数式编程主题。
最后,代码还会返回可能多次包含单个元素的列表 - 但我想这对你来说很好(例如intersection
返回intersection [1;1;1] [1]
但是如果你翻转参数你会得到只是[1;1;1]
)
答案 2 :(得分:1)
为了做到这一点,您需要跟踪正在构建的列表。执行此操作的最佳方法是定义一个辅助函数,该函数将列表构建为参数并将其包含在递归调用中
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 []
另一个评论是,在空列表中失败是不好的做法。只需将空列表视为没有元素的列表,因此不可能有交集
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 []
此版本有效,但最终会返回一个列表,其中的元素与它们在list1
中出现的顺序相反。为了解决这个问题,我们可以使用回调来按正确的顺序构建列表
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)
答案 3 :(得分:0)
我晚了1000年参加晚会,但是如果有人在这个问题上遇到困难,那么第一条评论中的答案对我不起作用。但是,这总是我的错,我对F#还是很陌生。我提出了以下似乎很好的方法。 欢迎提出任何有关改进的意见,因为我的代码可能很愚蠢。
ps。在这一点上,我不想使用内置运算符,因为我正在为一个类这样做。
ps1。我不想使用if
,我的教授更喜欢match
(为什么?)
let rec intersect =
function
| ([],[]) -> []
| ([],_) -> []
| (_,[]) -> []
| (x::xtail,y::ytail) -> match x=y with
| true -> x::intersect(xtail,ytail)
| false -> intersect(xtail,y::ytail)