函数关系运算符,类似于连接,在查询之外

时间:2017-12-17 19:52:30

标签: linq f#

假设我有两个有序的键值对集合,我需要对它们执行内部等连接以生成值对:seq<'a * 'b> -> seq<'a * 'c> -> seq<'b * 'c>

这很容易连接到System.Linq.Enumerable的扩展方法。

let foo abs acs =
    System.Linq.Enumerable.Join(abs, acs, 
        (fun ab -> fst ab), (fun ac -> fst ac),
        fun ab ac -> snd ab, snd ac )
foo ["A",1;"B",2] ["B",1;"C",2;"B",3]
// val it : System.Collections.Generic.IEnumerable<int * int> =
//  seq [(2, 1); (2, 3)]

将该功能转换为F#并不是那么简单。为了避免过滤笛卡尔积,我可能会根据需要失去一些懒惰/执行。

let bar abs acs = 
    let d = dict(Seq.groupBy fst acs) in seq{
        for a, b in abs do
            let ok, cs = d.TryGetValue a
            if ok then for c in cs -> b, snd c }
bar ["A",1;"B",2] ["B",1;"C",2;"B",3]
// val it : seq<int * int> = seq [(2, 1); (2, 3)]

然而,它感觉很狡猾,就像针对特定子问题的手工锻造,定制解决方案。我如何以更一般,抽象的方式处理relational operators,可能还有自然,半连接,反连接或外连接?

1 个答案:

答案 0 :(得分:3)

您可以使用query expression来实现同样的目标。

query {
  for a in ["A",1;"B",2] do
  join b in ["B",1;"C",2;"B",3] on (fst a = fst b)
  select (snd a, snd b) };;

val it : seq<int * int> = seq [(2, 1); (2, 3)]

或者,使用System.Linq.Enumerable.Join没有任何问题。