使用leftOuterJoin,不需要.DefaultIfEmpty() [英] With leftOuterJoin, .DefaultIfEmpty() is unnecessary

查看:236
本文介绍了使用leftOuterJoin,不需要.DefaultIfEmpty()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

leftOuterJoin MSDN上的查询表达式的文档反复暗示通过使用leftOuterJoin .. on .. into ..的示例,您仍然必须使用.DefaultIfEmpty()才能达到所需的效果.

The documentation for leftOuterJoin Query Expressions on MSDN repeatedly implies through the samples that when using leftOuterJoin .. on .. into .. that you must still use .DefaultIfEmpty() to achieve the desired effect.

我不认为这是必要的,因为我在这两个测试中都得到了相同的结果,只是第二个测试没有.DefaultIfEpmty()

I don't believe this is necessary because I get the same results in both of these tests which differ only in that the second one does not .DefaultIfEpmty()

type Test = A | B | C
let G = [| A; B; C|]
let H = [| A; C; C|]

printfn "%A" <| query {
    for g in G do
    leftOuterJoin h in H on (g = h) into I
    for i in I.DefaultIfEmpty() do 
    select (g, i)}

printfn "%A" <| query {
    for g in G do
    leftOuterJoin h in H on (g = h) into I
    for i in I do 
    select (g, i)}

// seq [(A, A); (B, null); (C, C); (C, C)]
// seq [(A, A); (B, null); (C, C); (C, C)]

1)您可以确认吗?

如果是正确的话,我只有在编写此备用类型增强以更好地处理无与伦比的结果之后才意识到这一点,我很惊讶仍然在输出中看到null

If that's right, I realized it only after writing this alternate type augmentation in an attempt to better deal with unmatched results and I was surprised to still see nulls in my output!

type IEnumerable<'TSource> with
    member this.NoneIfEmpty = if (Seq.exists (fun _ -> true) this) 
                              then Seq.map (fun e -> Some e) this 
                              else seq [ None ]

printfn "%A" <| query {
    for g in G do
    leftOuterJoin h in H on (g = h) into I
    for i in I.NoneIfEmpty do 
    select (g, i)}

// seq [(A, Some A); (B, Some null); (C, Some C); (C, Some C)]

2)是否可以从leftOuterJoin获取None而不是null/Some null?

2) Is there a way to get None instead of null/Some null from the leftOuterJoin?

3)我真正想做的是找出是否有不匹配的g

3) What I really want to do is find out if there are any unmatched g

printfn "%A" <| query {
    for g in G do
    leftOuterJoin h in H on (g = h) into I
    for i in I.NoneIfEmpty do
    where (i.IsNone)
    exists (true) }

我想出了下一个,但是它不是F#:

I figured this next one out but it isn't very F#:

printfn "%A" <| query {
    for g in G do
    leftOuterJoin h in H on (g = h) into I
    for i in I do
    where (box i = null) 
    exists (true)}

推荐答案

简短版本:查询表达式使用null.这是该语言中的一个粗糙之处,但是却是一个可以容忍的地方.

Short version: Query Expressions use nulls. It's a rough spot in the language, but a containable one.

我之前已经这样做过:

let ToOption (a:'a) =
    match obj.ReferenceEquals(a,null) with
    | true -> None
    | false -> Some(a)

这将使您能够做到:

printfn "%A" <| query {
    for g in G do
    leftOuterJoin h in H on (g = h) into I
    for i in I do 
    select ( g,(ToOption i))}

将每个结果包装在一个选项中(因为您不知道是否会有I.值得注意的是F#在运行时使用null表示None作为优化.因此请检查是否这确实是您想要的,对选项做出决定,例如:

Which wraps every result in an option (since you don't know if there is going to be an I. It's worth noting that F# uses null to represent None at run-time as an optimization. So to check if this is indeed what you want, make a decision on the option, like:

Seq.iter (fun (g,h) -> 
              printf "%A," g; 
              match h with 
              | Some(h) -> printfn "Some (%A)" h 
              | None -> printfn "None")  
    <| query {
    for g in G do
    leftOuterJoin h in H on (g = h) into I
    for i in I do 
    select ((ToOption g),(ToOption i))}

这篇关于使用leftOuterJoin,不需要.DefaultIfEmpty()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆