假设我有两个有序的键值对集合,我需要对它们执行内部等连接以生成值对: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,可能还有自然,半连接,反连接或外连接?
答案 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
没有任何问题。