【问题标题】:How do I combine these similar linq queries into one?如何将这些类似的 linq 查询合并为一个?
【发布时间】:2010-05-05 14:53:44
【问题描述】:

这可能是一个基本的 LINQ 问题。我需要选择一个对象,如果它为空,请选择另一个。我正在通过以下方式使用 linq to objects,我知道可以更快、更好、更清洁地完成...

    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 子句上有所不同,我知道有一种方法可以将它们结合起来。任何想法将不胜感激。

【问题讨论】:

  • 您应该使用 .Any() 而不是 .Count()。 Count() 遍历整个序列,而 Any 只是检查第一项是否存在。
  • @MikeD:需要注意的是上面的代码不能编译,因为在两个序列都没有你要找的项目的情况下你不会返回一个值。
  • 抱歉,我正试图在 SO 窗口中将我的方法整理成简洁的内容,但显然删除了太多内容。

标签: c# linq


【解决方案1】:

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

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;
}

【讨论】:

    【解决方案2】:

    这不使用查询语法,但它保留了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();
    }
    

    【讨论】:

      【解决方案3】:
       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();
      

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

      【讨论】:

      • 您可以使用 orderby 来确保检索项目的顺序。
      • @codymanix:您必须指定一个自定义比较器,以便 ActionTypeOne 类型的元素在 ActionTypeTwo 类型的元素之前返回(不能保证默认情况下它们会以这种方式排序) .它还需要可以在线性时间内运行的东西并将其转换为 n log(n)。 99% 的时间都没有关系,但要注意一些事情。
      【解决方案4】:

      我建议:

       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();
       }
      

      【讨论】:

        【解决方案5】:
         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 查询将是(我使用了 Case 语句,因为我不知道 ActionType 列的数据类型):

        Select TOP 1 id, name
        From Actions
        where ActionType In(ActionTypeOne, ActionTypeTwo)
        Order By Case ActionType When 1 Then 0 Else 1 End ASC
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-06-13
          • 1970-01-01
          • 2012-09-12
          • 2011-06-28
          相关资源
          最近更新 更多