2012-05-17 32 views
4

我最近發現了LINQ,我覺得它非常有趣。目前我有以下功能,而且我不確定它是否會更高效,畢竟產生相同的輸出。簡單操作中LINQ的效率

您能否告訴我您對此的看法?

private static byte[] FilterText(byte[] arr) 
    { 
     List<byte> filteredBytes = new List<byte>(); 
     int j = 0; //index for filteredArray 

     for (int i = 0; i < arr.Length; i++) 
     { 
      if ((arr[i] >= 65 && arr[i] <= 90) || (arr[i] >= 97 && arr[i] <= 122) || arr[i] == 10 || arr[i] == 13 || arr[i] == 32) 
      { 
       filteredBytes.Insert(j, arr[i]) ; 
       j++; 
      } 
     } 

     //return the filtered content of the buffer 
     return filteredBytes.ToArray(); 
    } 

的LINQ替代:

private static byte [] FilterText2(byte[] arr) 
    { 
     var x = from a in arr 
       where ((a >= 65 && a <= 90) || (a >= 97 && a <= 122) || a == 10 || a == 13 || a == 32) 
       select a; 

     return x.ToArray(); 
    } 
+3

爲什麼你有'j'?只需使用「添加」而不是「插入」,您可以免除該計數器。 –

+0

你可能應該替換'.Insert(j,''部分用'.Add('和刪除'j'計數器。 – Douglas

+0

是的謝謝你,我只是修改了代碼,甚至沒有安排! – test

回答

14

LINQ通常是稍大於簡單循環和程序代碼效率較低,但不同的是

的功能簡單地以非常簡單的方式移除標點符號通常很小,閱讀的簡潔性和易用性通常會使其將簡單的投影和過濾轉換爲LINQ。

如果性能確實很重要,那麼測量它並自行決定LINQ代碼的性能是否足夠。

+3

同意@Mark。與調試代碼相比,您將購買更多使用linq的時間 –

+3

除非你會來調試複雜的linq查詢,這可能會很棘手 - 這並不意味着我不會使用它 –

4

LinQ非常適合簡單。性能明智,如果您開始對列表,數組等進行大量轉換,它確實會成爲一個問題。

MyObject.where(...).ToList().something().ToList().somethingelse.ToList(); 

這是衆所周知的殺手,試圖儘可能晚地轉換到最終名單。

+1

+1:好點。如果您需要對返回的序列進行進一步的過濾/排序/操作,那麼最好將它作爲'Enumerable '而不帶'ToArray()'返回。 – Douglas

+0

@Douglas我認爲你的意思是'IEnumerable '('Enumerable'是一個靜態類),但另有約定。 –

+0

@AdamMihalcin:你是對的;感謝您指出了這一點。 – Douglas

4

螺絲性能,LINQ是要命的,因爲這樣的:

private static bool IsAccepted(byte b) 
{ 
    return (65 <= b && b <= 90) || 
      (97 <= b && b <= 122) || 
      b == 10 || b == 13 || b == 32; 
} 

arr.Where(IsAccepted).ToArray(); // equivalent to FilterText(arr) 

即你不會寫下如何,而只是寫什麼。此外,它與您提供的其他方法一樣快(緩慢):Where(..)ToArray()中得到延遲評估,它在內部創建一個List並將其轉換爲Array iirc。

順便說一下,字符串在C#中是Unicode的,所以不要用它來做一些簡單的字符串格式化(有更好的替代方案)。

+0

謝謝隊友!我正在做它去除一些標點符號:) – test

2

大多數情況下,我同意@MarkByers。 Linq的效率會比程序代碼低一點。一般來說,缺陷可以追溯到編譯表達式樹。儘管如此,時間改進的可讀性在99%的案例中值得打擊。當遇到性能問題時,進行基準測試,修改和重新測試。

就這麼說,LINQ與lambda表達式和匿名代表關係非常密切。這些功能經常被討論,就好像它們是同一件事一樣。有其中這些構造可以比程序代碼更快它看起來像你的例子可以是其中的一種情況。我會重寫您的代碼,如下所示:

private static byte [] FilterText2(byte[] arr) { 

    return arr.Where(a=> (a >= 65 && a <= 90) || 
         (a >= 97 && a <= 122) || 
          a == 10 || a == 13 || a == 32 
       ).ToArray(); 
} 

再次,爲您的特定場景做一些基準標記,如YMMV。大量的墨水已經溢出,並且在哪些情況下更快。下面是一些墨水:

1

Many LINQ statements are easily parallelizable.只需添加AsParallel()到查詢的開始。如果您想要保留原始訂單而犧牲一些性能,您還可以添加AsOrdered()。例如,下面的LINQ聲明:

arr.Where(IsAccepted).ToArray(); 

可以寫爲:

arr.AsParallel().AsOrdered().Where(IsAccepted).ToArray(); 

你只需要確保its overhead doesn't outweigh its benefits

var queryA = from num in numberList.AsParallel() 
      select ExpensiveFunction(num); //good for PLINQ 

var queryB = from num in numberList.AsParallel() 
      where num % 2 > 0 
      select num; //not as good for PLINQ 
1

每一個良好的書面命令式代碼會更時間和空間都比好的書面聲明代碼有效,因爲聲明式代碼必須翻譯成命令式的代碼(除非你擁有一臺Prolog機器......你可能不需要,因爲使用你在問.Net :-))。

但是,如果您可以使用LINQ以比使用循環更簡單,更可讀的方式解決問題,那就值得。當你看到類似

var actualPrices = allPrices 
    .Where(price => price.ValidFrom <= today && price.ValidTo >= today) 
    .Select(price => price.PriceInUSD) 
    .ToList(); 

這是「一行」,它明顯地表明它在第一眼看到的是什麼。聲明一個新的集合,循環遍歷舊集合,如果寫入新的集合並添加新內容,則不是。所以如果你不想每毫秒節省一次(這可能不會,因爲你使用.Net而不是C嵌入式ASM),這是一個勝利。 LINQ被高度優化 - 有更多的代碼庫 - 一個用於集合,一個用於XML,一個用於SQL ...,所以它通常不會太慢。沒有理由不使用它。使用並行LINQ可以很容易地並行化一些LINQ表達式(=沒有更多的代碼,但並行開銷仍然存在,因此需要考慮)。