【问题标题】:Intersect using custom function in f#在 f# 中使用自定义函数相交
【发布时间】:2021-09-20 15:51:56
【问题描述】:

我有两个列表。第一个是具有 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)

【问题讨论】:

  • 你的括号仍然在错误的地方;)

标签: .net linq f#


【解决方案1】:

在 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" }]

【讨论】:

  • 是的 - 你是对的。但是,更正逗号(就像我现在在原始问题中所做的那样)仍然会产生相同的编译器错误。
  • @MattAustin 我认为您需要分享更多代码。我在答案中添加了一个完整的示例。
  • 非常感谢!根据您的 sn-p 我看到我搞砸了函数中的括号。我会用(非常简单的)修复来更新我的问题。
猜你喜欢
  • 2019-12-16
  • 1970-01-01
  • 2014-09-30
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 2014-05-21
  • 2013-11-04
相关资源
最近更新 更多