在 f# 中使用自定义函数相交
Intersect using custom function in f#
我有两个列表。第一个是具有 Id 属性 的结构化记录列表,其中 Id 是一个字符串包装器。第二个是一个简单的字符串列表。
我需要在第一个列表中找到其 ID 在第二个集合中出现的所有记录。
在 c# 中,这将是微不足道的:
var intersect = list1.Where(x => list2.Contains(x.Id.ToString()))
也许有更有效的方法来获取交集,但是 c# 和 linq 使得获取所需的输出变得非常容易。
我是 f# 的新手,但在 f# 中这似乎是一个非常重要的操作。 f# 中的 Linq 不支持 lambda 比较器函数(据我所知),内置的过滤器函数似乎依赖于两个列表中实体之间的直接比较(指定自定义比较器并不容易)。
我试过以下方法:
list1 |> List.filter(fun x -> List.contains (x.Id.ToString() list2))
...但这会产生以下编译器错误:
This expression was expected to have type
'bool'
but here has type
''a list -> bool'
我真的希望有人会告诉我,我很笨,在 f# 中有一个非常简单的方法来做到这一点...拜托!
回答
原来是我的语法搞砸了。我 认为 需要下面的括号来强制 x.Id.ToString() 首先求值,但是参数周围的括号 List.contains 不是必需的
list1 |> List.filter(fun x -> List.contains (x.Id.ToString()) list2)
在 F# 中,函数参数由 空格 分隔,而不是逗号,每个参数周围的括号是可选的。您没有将整个参数列表括起来的括号 - 这将表示一个元组。
您写了:
list1 |> List.filter(fun x -> List.contains (x.Id.ToString(), list2))
但你可能是这个意思:
list1 |> List.filter (fun x -> List.contains (x.Id.ToString()) list2)
完整示例(放入 .fsx
文件):
type Foo =
{
Id : string
}
let list1 =
[
{ Id = "a" }
{ Id = "b" }
{ Id = "x" }
]
let list2 =
[
"a"
"b"
"c"
]
let list3 =
list1 |> List.filter (fun x -> List.contains (x.Id.ToString()) list2)
printfn "%A" list3
// [{ Id = "a" }; { Id = "b" }]
我有两个列表。第一个是具有 Id 属性 的结构化记录列表,其中 Id 是一个字符串包装器。第二个是一个简单的字符串列表。
我需要在第一个列表中找到其 ID 在第二个集合中出现的所有记录。
在 c# 中,这将是微不足道的:
var intersect = list1.Where(x => list2.Contains(x.Id.ToString()))
也许有更有效的方法来获取交集,但是 c# 和 linq 使得获取所需的输出变得非常容易。
我是 f# 的新手,但在 f# 中这似乎是一个非常重要的操作。 f# 中的 Linq 不支持 lambda 比较器函数(据我所知),内置的过滤器函数似乎依赖于两个列表中实体之间的直接比较(指定自定义比较器并不容易)。
我试过以下方法:
list1 |> List.filter(fun x -> List.contains (x.Id.ToString() list2))
...但这会产生以下编译器错误:
This expression was expected to have type
'bool'
but here has type
''a list -> bool'
我真的希望有人会告诉我,我很笨,在 f# 中有一个非常简单的方法来做到这一点...拜托!
回答
原来是我的语法搞砸了。我 认为 需要下面的括号来强制 x.Id.ToString() 首先求值,但是参数周围的括号 List.contains 不是必需的
list1 |> List.filter(fun x -> List.contains (x.Id.ToString()) list2)
在 F# 中,函数参数由 空格 分隔,而不是逗号,每个参数周围的括号是可选的。您没有将整个参数列表括起来的括号 - 这将表示一个元组。
您写了:
list1 |> List.filter(fun x -> List.contains (x.Id.ToString(), list2))
但你可能是这个意思:
list1 |> List.filter (fun x -> List.contains (x.Id.ToString()) list2)
完整示例(放入 .fsx
文件):
type Foo =
{
Id : string
}
let list1 =
[
{ Id = "a" }
{ Id = "b" }
{ Id = "x" }
]
let list2 =
[
"a"
"b"
"c"
]
let list3 =
list1 |> List.filter (fun x -> List.contains (x.Id.ToString()) list2)
printfn "%A" list3
// [{ Id = "a" }; { Id = "b" }]