左连接LINQ并使用Bitwise Comparisons

时间:2010-11-14 20:33:42

标签: linq linq-to-objects

左连接LINQ并使用Bitwise Comparisons。

我有一个可以描述的问题(感谢David B澄清这一点): 目标是从左表中返回每个OID 1行,其中左表中的记录计数等于右表中匹配行的计数。当一行中的OAG,RID和FLAG设置为FLAGS时,记录匹配。

我们正在比较的对象具有以下结构:

public class Roads : List<Road>{}
public class Road
{
    public int RID;
    public int OID;
    public int Check = 1;
    public long Flag;
}
public class Cars : List<Car> { }
public class Car
{
    public int RID;
    public int OID;
    public long Flags;
}

对象a填充了以下数据。

        Roads rs = new Roads();
        Cars cs = new Cars();

        Car c = new Car();
        c.OID = 1;
        c.RID = 1;
        c.Flags = 31; // 11111
        cs.Add(c);
        c = new Car();
        c.OID = 1;
        c.RID = 2;
        c.Flags = 31; //11111
        cs.Add(c);
        c = new Car();
        c.OID = 1;
        c.RID = 3;
        c.Flags = 4; //00100
        cs.Add(c);

        Road r = new Road();
        r.OID = 1;
        r.RID = 1;
        r.Flag = 8; //00010
        rs.Add(r);
        r = new Road();
        r.OID = 1;
        r.RID = 2;
        r.Flag = 2; //01000
        rs.Add(r);
        r = new Road();
        r.OID = 1;
        r.RID = 3;
        r.Flag = 4;  //01000
        rs.Add(r);
      //  r = new Road();
      //  r.OID = 1;
      //  r.RID = 3;
      //  r.Flag = 16;  //00001
      //  rs.Add(r);

要查看是否设置了标志,请进行逐位比较,即cs [0] .Flags&amp;&amp; rs [0] .Flag&gt; 0为TRUE,cs [0] .Flags&amp; rs [0] .Flag = 0为FALSE

我有这个通用查询,它将获取cs中OID计数= rs中匹配OID计数的行。我现在需要一个修改过的查询,其中应用了其余的规则。我们在哪里检查Flag是否在特定行匹配的标志中。

    var carLookup = cs.ToLookup(cb => c.OID);
    var roadLookup = rs.ToLookup(rb => r.OID);

    var results1 = from x in carLookup
                   let carCount = x.Count()
                   let roadCount = roadLookup[x.Key].Count()
                   where carCount == roadCount
                   select new {  OID = x.Key, CarCount = carCount, RoadCount = roadCount };

如何扩展此功能以应用其他过滤条件?我正在努力的是在我需要它们的地方可以建立适当的过滤条件。例如,我需要比较Flags&amp;&amp;旗。但是我如何才能获得Flag和Flags以进行额外的过滤?

展开。我主要使用TSQL,所以我试图模仿我可以轻松应用于TSQL的逻辑流程。如果我用TSQL做这个,它看起来像这样(注意0的特殊情况):

SELECT cs.OID, Count(cs.OID) AS CarCount, Sum(RS.Check) AS RoadCount  
   FROM Cars AS cs  
LEFT JOIN Roads AS RS  
  ON CS.oid = RS.OID  
 AND cs.RID = RS.RID  
 AND (CS.FLAGS & RS.FLAG > 0
      OR (CS.FLAGS=0 AND RS.FLAG=0))
GROUP BY cs.OID  
HAVING Count(cs.OID) = Sum(RS.Check)   

使用该语句和上面的数据,结果将是 1,3,3。

如果我要评论最后一次添加到Roads,并取消注释下一行,将Flag更改为16,那么结果将是: 空值 如果您需要更多信息,请发表评论。

1 个答案:

答案 0 :(得分:0)

我认为这应该等同于您的SQL语句,但是由于您的SQL使用RS.Check但是您没有在示例代码中分配任何Check值,因此它没有产生您提到的结果(您使用r.OID)。我继续将r.Check = 1;添加到每个Road对象中,并且能够获得您提到的结果。

var query = from car in cs
            from road in rs
            where car.OID == road.OID
                && car.RID == road.RID
                && ((car.Flags & road.Flag) > 0 || (car.Flags == 0 && road.Flag == 0))
            group new { car, road } by car.OID into grouping
            let CarCount = grouping.Count()
            let RoadCount = grouping.Sum(o => o.road.Check)
            where CarCount == RoadCount
            select new { OID = grouping.Key, CarCount, RoadCount };