2010-05-04 107 views
1

这可能是一个基本的LINQ问题。我需要选择一个对象,如果它是空的选择另一个。我使用LINQ to对象以下列方式,我知道可以做到更快,更好,更清洁......如何将这些相似的linq查询合并为一个?

public Attrib DetermineAttribution(Data data) 
    { 

     var one = from c in data.actions 
          where c.actionType == Action.ActionTypeOne 
          select new Attrib 
             { 
              id = c.id, 
              name = c.name 
             }; 
     if(one.Count() > 0) 
      return one.First(); 

     var two = from c in data.actions 
        where c.actionType == Action.ActionTypeTwo 
        select new Attrib 
          { 
           id = c.id, 
           name = c.name 
          }; 
     if (two.Count() > 0) 
      return two.First(); 

    } 

两个LINQ操作上区别仅在where子句,我知道有一种方法将它们结合起来。任何想法将不胜感激。

+1

您应该使用.Any()而不是.Count()。 Count()遍历整个序列,而Any只检查第一个项目是否存在。 – Rubys 2010-05-04 15:52:36

+0

@MikeD:应该指出的是,上面的代码不能编译,因为在两个序列没有你正在寻找的项目的情况下,你不会返回一个值。 – casperOne 2010-05-04 15:59:53

+0

对不起,我试图把我的方法清理成SO窗口中的简明内容,显然太多了。 – MikeD 2010-05-04 16:54:41

回答

6

我觉得这个解决方案简单高效:

public Attrib DetermineAttribution(Data data) 
{ 
    var c = data.actions.FirstOrDefault(c => c.actionType == Action.ActionTypeOne) ?? 
      data.actions.FirstOrDefault(c => c.actionType == Action.ActionTypeTwo); 
    return c != null ? new Attrib { id = c.id, name = c.name } : null; 
} 
+0

绝对简单 – R0MANARMY 2010-05-04 16:00:27

0
var one = (from c in data.actions 
          where (c.actionType == Action.ActionTypeOne) || (c.actionType == Action.ActionTypeTwo) 
          select new Attrib 
             { 
              id = c.id, 
              name = c.name 
             }).FirstOrDefault(); 

这并不能保证在ActionTypeTwo之前会发现ActionTypeOne。它找到第一条记录ActionTypeOne ActionTypeTwo。

+0

您可以使用orderby来确保检索项目的顺序。 – codymanix 2010-05-04 15:28:24

+0

@codymanix:您必须指定一个自定义比较器,以便在ActionTypeTwo类型的元素之前返回类型为“ActionTypeOne”的元素(并不保证它们将按默认方式进行排序)。它也需要一些能够以线性时间运行并将其转换为n log(n)的东西。 99%的时间无关紧要,但有一点要注意。 – R0MANARMY 2010-05-04 15:34:27

1

这不使用查询语法,但它保留了ActionTypeOne类型的元素在ActionTypeTwo的元素之前返回的逻辑。由于懒惰的评估,除非没有ActionTypeOne类型的元素,否则第二个查询将不会执行。

public Attrib DetermineAttribution(Data data) 
{ 

    return data.actions.Where(c => c.actionType == Action.ActionTypeOne) 
       .Concat(data.actions.Where(c.actionType == Action.ActionTypeTwo)) 
       .Select(c => new Attrib 
         { 
          id = c.id, 
          name = c.name 
         }) 
       .FirstOrDefault(); 
} 
0

我建议:

public Attrib DetermineAttribution(Data data) 
{ 
     var types = Enum.GetValues(typeof (Action)).Cast<Action>(); 
     var merged = from c in data.actions 
        from t in types 
        where c.actionType == t 
        select new Attrib {id = c.id, name = c.name}; 

     return merged.FirstOrDefault(); 
} 
0
var one = from c in data.actions 
       where c.actionType == Action.ActionTypeOne 
        || c.actionType == Action.ActionTypeTwo 
       orderby c.actionType == Action.ActionTypeOne ? 0 : 1 
       select new Attrib 
           { 
            id = c.id, 
            name = c.name 
           }).FirstOrDefault(); 

等价的SQL查询将是(我用了一个案例陈述,因为我不知道操作类型列的数据类型):

​​