List 如何搜索元组元素的列表?
在我的任务中,我必须列出婚礼上不能坐在一起的人的名单。然后将其与桌子上的人员列表进行比较。如果同一元组中的任意两个人在表列表中,则该值应为false。否则是真的。这是我第一次用F#编写代码,所以这里的语法让我很头疼List 如何搜索元组元素的列表?,list,f#,tuples,return-value,List,F#,Tuples,Return Value,在我的任务中,我必须列出婚礼上不能坐在一起的人的名单。然后将其与桌子上的人员列表进行比较。如果同一元组中的任意两个人在表列表中,则该值应为false。否则是真的。这是我第一次用F#编写代码,所以这里的语法让我很头疼 let isValidTable (cantSit:(string*string) list) (people: string list) = let truth = true; let rec matchPeople cantSit person1 person2
let isValidTable (cantSit:(string*string) list) (people: string list) =
let truth = true;
let rec matchPeople cantSit person1 person2=
match cantSit with
| [] -> None
| head :: tail ->
let (person1,person2) = head
if ((List.exists(fun names -> names = person1) people) && (List.exists(fun names2 -> names2 = person2) people)) then
let result2 = false
else
matchPeople tail fst snd;;
let result = true;;
matchPeople cantSit fst snd;;
let x = [("Eric", "Mark"); ("Anna", "Maya"); ("Beth", "Hope")];;
let weddingList = ["Eric"; "Anna"; "Beth"]
let validOrNah = isValidTable x weddingList;;
printf("\n%O") validOrNah;;
对我来说,问题是我不断地遇到诸如“matchPeople构造函数未定义”或“let is unfinished”之类的错误。任何帮助都将不胜感激,谢谢
以前:我有
if(first person is in list and second person is in list)
then Some false
else recursive statement;
此代码编译时没有错误,但仅打印为null。我知道变量在F#中是不可变的,这使得这很困难。代码中有很多问题,都是由于不熟悉F#造成的。我会一行一行地看一遍,试着解释一下你还没有理解的东西
let isValidTable (cantSit:(string*string) list) (people: string list) =
这很好
let truth = true;
| [] -> None
let (person1,person2) = head
根本不需要这个任务,因为您在代码中的任何地方都不使用名称truth
。如果您确实需要使用它,您可以将其替换为常量true
,这样它的可读性会更好。让我们完全删除这一行
顺便说一句,与类C语言不同,F#中的行尾不需要分号。双分号仅在F#交互式解释器中使用,用于告诉解释器“我已输入完此表达式”。这允许您将表达式拆分为多行,而无需解释器猜测何时完成(因为F#中的许多部分表达式看起来是完整的,因此需要显式表达式终止)。我不会在每次出现分号时都提到这一点,但您可以删除行末尾的所有分号(和双分号)。F中唯一需要分号的地方是列表中的项目之间,例如在x
或weddingList
中
转到下一行
let rec matchPeople cantSit person1 person2=
else
这看起来不错,但实际上,您根本不需要person1
和person2
参数。我的猜测是,参数列表中有它们,因为您认为在创建变量之前需要声明变量,但F#根本不是这样工作的。在函数的后面编写let(person1,person2)=head
时,变量person1
和person2
就在那里创建,不需要将它们作为函数参数。因此,您可以删除它们,您的函数定义将变成let rec matchPeople cantSit=
match cantSit with
这很好
let truth = true;
| [] -> None
let (person1,person2) = head
这是一个小错误。在其他地方,您似乎希望返回布尔值,但在这里,您将返回一个选项。在F#中,match
和/或if…else
的所有分支必须返回相同的类型。您的isValidTable
函数显然是要返回布尔值,matchPeople
也是如此,因此这也应该是一个布尔值。问题是,这行应该返回false
还是true
?要回答这个问题,请思考空的cantSit
列表在问题域的语义中意味着什么。这意味着没有人不能坐在一起,所以座位表是有效的,无论是谁在桌子上。当然,这也可能意味着您已经通过多次递归调用到达了cantSit
列表的末尾,在这种情况下,您在这里返回的值将是最后一次递归调用返回的值。同样,返回true
是您想要的,因为如果您之前发现了一个无效的坐姿对,您将立即返回false
,而不会进行另一个递归调用。因此,如果您到达cantSit
列表为空的点,那么您就可以返回true
| head :: tail ->
这很好
let truth = true;
| [] -> None
let (person1,person2) = head
这不仅很好,还很好
if ((List.exists(fun names -> names = person1) people) && (List.exists(fun names2 -> names2 = person2) people)) then
这很好,但可以简化。这里有一个列表。包含满足您需要的函数。任何类型的调用List.exists(fun item->item=value)itemList)
都可以简化为List.contains item itemList
。因此,如果(List.containmentperson1-people)和(List.containmentperson2-people),那么这将成为,它更容易阅读和快速理解
let result2 = false
这是错误的;F#中的let
赋值没有值,因为它是if
块中的最后一个表达式,这意味着如果条件为真,则if
块将没有值。这就是为什么会出现“未完成”错误:在F#中,let
赋值可能永远不会是代码块的最后一个表达式。它后面必须始终跟有值的表达式。实际上,您在这里要做的是非常清楚的:如果两个人都在列表中,您希望返回false
。您可以通过在这行中写入false
来实现这一点;我在这里再解释一下
在F#中,if…else
是一个返回值的表达式,而不是像大多数其他语言那样的语句。所以你可以这样写:
let n = 5
let s = if n % 2 = 0 then "Even" else "Odd"
printfn "%s" s // Prints "Odd"
这里,您的if…else
是match
表达式的最后一行,因此它的值将是match
表达式的值。而match
表达式是matchPeople
函数的最后一个表达式,因此其值将是函数的返回值。因此,如果您发现一个匹配的对不能放在一起(这个if…else
表达式的真正分支),那么您只需要有一行代码告诉您false
,如果它碰到该分支,这将是函数的返回值
继续下一行
let rec matchPeople cantSit person1 person2=
else
显然,这很好
matchPeople tail fst snd;;
一旦您删除了fst
和snd
(因为我们更改了函数签名,所以matchPeople
现在只需要一个参数