2015-02-10 25 views
0

,其存儲std::vector<int>內部可以很容易地使用該子集索引如下暴露子集的迭代器的一類:子集迭代器在C#陣列/列表而不屈服

開始:

return _data.begin() + _subset_begin; 

端:

return _data.begin() + _subset_end; 

有沒有一種有效的方式在C#中做到這一點?基於產量的最初實施非常緩慢。

for(int i = _subset_begin; i < _subset_end; ++i) 
{ 
    yield return _data[i]; 
} 

如何有效解決此問題?

我知道它不完全相同,因爲C++使用迭代器作爲返回類型,而C#使用IEnum;但這些是每種語言的約定......

+0

是由[ArraySegment](https://msdn.microsoft.com/en-露出的迭代us/library/1hsbd92d%28v = vs.110%29.aspx)更高性能?另外:您是否在調試器外部測試RELEASE生成運行? – 2015-02-10 12:58:02

+0

ArraySegment是解決方案。作出答案,我會接受它。 – Wilbert 2015-02-10 13:18:27

+0

我寫了一個更詳細的答案。 :) – 2015-02-10 13:20:37

回答

1

如果您使用的是Linq,那麼使用原始數組還是換行數組實際上幾乎沒有什麼區別。

爲了測試這一點,我寫了下面的程序:

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

namespace Demo 
{ 
    public static class Program 
    { 
     private static void Main() 
     { 
      var sw = new Stopwatch(); 

      int[] array = new int[1000000]; 

      int loops = 100; 

      for (int trial = 0; trial < 4; ++trial) 
      { 
       sw.Restart(); 

       for (int i = 0; i < loops; ++i) 
        subsetViaArraySegment(array, 0, array.Length).Sum(); 

       Console.WriteLine("subsetViaArraySegment() took " + sw.Elapsed); 
       sw.Restart(); 

       for (int i = 0; i < loops; ++i) 
        subsetViaYield(array, 0, array.Length).Sum(); 

       Console.WriteLine("subsetViaYield() took " + sw.Elapsed); 
       sw.Restart(); 

       for (int i = 0; i < loops; ++i) 
        array.Sum(); 

       Console.WriteLine("Simple Sum() took " + sw.Elapsed); 
       sw.Restart(); 

       for (int i = 0; i < loops; ++i) 
       { 
        int total = 0; 

        for (int j = 0, n = array.Length; j < n; ++j) 
        { 
         unchecked 
         { 
          total += array[j]; 
         } 
        } 
       } 

       Console.WriteLine("Inline code took " + sw.Elapsed); 
       Console.WriteLine(""); 
      } 
     } 

     private static IEnumerable<int> subsetViaYield(int[] source, int start, int count) 
     { 
      for (int i = start, n = start + count; i < n; ++i) 
       yield return source[i]; 
     } 

     private static IEnumerable<int> subsetViaArraySegment(int[] source, int start, int count) 
     { 
      return new ArraySegment<int>(source, start, count); 
     } 
    } 
} 

它測試才能使用LINQ使用ArraySegment,產量實現總結在一個大陣列中的所有整數多久,剛生陣列本身。它也可以在不使用Linq的情況下進行內聯計算。是

在Windows 8.1 x64的發佈版本運行結果如下:

subsetViaArraySegment() took 00:00:00.6924651 
subsetViaYield() took 00:00:00.9207855 
Simple Sum() took 00:00:00.9876048 
Inline code took 00:00:00.0884620 

subsetViaArraySegment() took 00:00:01.0222854 
subsetViaYield() took 00:00:00.9309415 
Simple Sum() took 00:00:01.0031804 
Inline code took 00:00:00.0890534 

subsetViaArraySegment() took 00:00:01.0146586 
subsetViaYield() took 00:00:00.9129277 
Simple Sum() took 00:00:00.9842326 
Inline code took 00:00:00.0890593 

subsetViaArraySegment() took 00:00:01.0306027 
subsetViaYield() took 00:00:00.9353762 
Simple Sum() took 00:00:00.9902355 
Inline code took 00:00:00.0879321 

注意的LINQ如何處理都採取了類似的時間 - 和內嵌代碼是快許多倍。

因此,如果你真的需要最快的代碼,你不應該使用Linq。相反,您可以使用ArraySegment來包裝數組,然後編寫使用數組段定義的子集的代碼。

例如,函數來計算一個整數陣列段的總和可能看起來像這樣:

public static long Sum(ArraySegment<int> arraySegment) 
{ 
    long total = 0; 
    var array = arraySegment.Array; 

    for (int i = arraySegment.Offset, n = i + arraySegment.Count; i < n; ++i) 
     total += array[i]; 

    return total; 
}