2013-03-07 110 views
0

我试图从我连接它们的库对象列表中获取数据深入到我的信息对象中。两种解决方案我都看起来效率很低。如果linq查询不是更长的变体,有什么办法可以将它减少为单个OfType调用?在信息对象列表上调用linq最有效的方法是什么?

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace LinqQueries 
{ 

    // Test the linq queries 
    public class Test 
    { 
     public void TestIt() 
     { 
      List<ThirdParty> As = new List<ThirdParty>(); 

      // This is nearly the query I want to run, find A and C where B 
      // and C match criteria 
      var cData = from a in As 
         from b in a.myObjects.OfType<MyInfo>() 
         where b.someProp == 1 
         from c in b.cs 
         where c.data == 1 
         select new {a, c}; 

      // This treats A and B as the same object, which is what I 
      // really want, but it calls two sub-queries under the hood, 
      // which seems less efficient 
      var cDataShorter = from a in As 
           from c in a.GetCs() 
           where a.GetMyProp() == 1 
           where c.data == 1 
           select new { a, c }; 
     } 
    } 

    // library class I can't change 
    public class ThirdParty 
    { 
     // Generic list of objects I can put my info object in 
     public List<Object> myObjects; 
    } 

    // my info class that I add to ThirdParty 
    public class MyInfo 
    { 
     public List<C> cs; 
     public int someProp; 
    } 

    // My extension method for A to simplify some things. 
    static public class MyExtentionOfThirdPartyClass 
    { 
     // Get the first MyInfo in ThirdParty 
     public static MyInfo GetB(this ThirdParty a) 
     { 
      return (from b in a.myObjects.OfType<MyInfo>() 
        select b).FirstOrDefault(); 
     } 

     // more hidden linq to slow things down... 
     public static int GetMyProp(this ThirdParty a) 
     { 
      return a.GetB().someProp; 
     } 

     // get the list of cs with hidden linq 
     public static List<C> GetCs(this ThirdParty a) 
     { 
      return a.GetB().cs; 
     } 
    } 

    // fairly generic object with data in it 
    public class C 
    { 
     public int data; 
    } 
} 
+1

运行这两个查询并用秒表计时。请注意延迟执行。 – 2013-03-07 21:41:48

+0

LINQ针对可读性和易开发性进行了优化 - 而不是执行速度。如果存在性能问题,请尝试用一些循环替换LINQ。做一些时间来验证速度,并在循环上面写一条评论来解释它在做什么。 – 2013-03-07 21:49:12

+1

@DasKrümelmonster鉴于在这里执行的操作是什么,我的猜测是LINQ应用的开销将会小到可以忽略,因为真正的“工作”不是微不足道的。当真正的“工作”要做的非常快,并且有很多项目时,LINQ开销会开始被注意到。你需要确定个人资料,但赔率不够重要。 – Servy 2013-03-07 21:50:43

回答

1

很不幸,答案是“这取决于”。我不得不用两种方式编写查询,并对其执行计时。

1000个第三方对象,每个1个MyObject,每个1000个c,所有结果匹配标准,第一个查询的速度是两倍。如果没有MyObjects匹配条件,则查询1的速度要快两个数量级。但是,如果您有多个MyObjects,则效率会反转,100个ThirdParty,100个MyObjects,每个100个C,所有结果匹配,第二个查询比第一个快两个数量级。没有MyObjects匹配,第一个出来更快。

我实际上最终实现了较慢的解决方案,因为它使代码更干净,并且较慢的查询性能并不是那么糟糕。

1

如果你说你的cDataShorter是产生正确的结果,那么你可以把它改写这样的:

As.SelectMany(a => a.myObjects, (aa, mo) => new R {Tp = aa, Mi = mo as MyInfo}) 
    .Where(r => r.Mi != null && r.Mi.someProp == 1) 
    //.Distinct(new Comparer<R>((r1, r2) => r1.Tp.Equals(r2.Tp))) 
    // If you need only one (first) MyInfo from a ThirdParty 
    // You don't need R if you're not going to use Distinct, just use an anonymous 
    .SelectMany(r => r.Mi.cs, (rr, c) => new {a = rr.Tp, c}) 
    .Where(ao => ao.c.data == 1)  

public class R { 
    public ThirdParty Tp; 
    public MyInfo Mi; 
} 

为简单起见,Comparerthere

+0

这个解决方案效率相同,GetMyProp和GetCs都像我的第二个例子那样运行子查询。 – 2013-03-07 23:18:11

+0

@Denise Skidmore,好吧,没有子查询的解决方案。检查我的更新。 – aush 2013-03-08 00:08:18

相关问题