2013-03-07 50 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

相關問題