2012-02-29 109 views
3

的通用初始化我有一個多維數組,我想在一個簡單快速的方法來初始化:多維數組

double[,,] arr = new double[4,5,6]; 
// doesn't work by design 
foreach(double d in arr) 
    d = ... ; // my initialization value 

這顯然不工作。但我想有一個通用函數來將所有數組值設置爲選擇的默認值。有了自己的類,我可以編寫一個特殊的構造函數,但是對於值類型我沒有真正的想法。使用C++,我可以用一個for循環以線性方式訪問所有項目,但在C#中,我認爲我必須儘可能多地使用循環,因爲我有尺寸。目前我還沒有更好的解決方案(或者我正在使用不安全的代碼和指針算術,這可能會起作用)。

有沒有更好的方法來做到這一點?

+2

如果您關注的是速度,不要使用多維數組。它們在.NET中非常緩慢(與單維數組相比)。儘管指針追逐,即使參差不齊的數組也更快。這裏最簡單+最快的事情就是使它成爲一維,並自己進行索引數學運算。 – harold 2012-02-29 09:48:38

+0

這是以某種方式相關,並發現它很有趣:http://stackoverflow.com/questions/136836/c-sharp-array-initialization-with-non-default-value – mindandmedia 2012-02-29 09:51:15

+0

感謝您的意見,速度實際上不是一個問題我目前的應用程序,但我更喜歡這裏乾淨的語法。 – 2012-02-29 09:56:36

回答

3

不太確定它是否是你想要的,但下面的擴展方法將允許你初始化數組中的每個值,而不管維數有多少。

public static class ArrayExtensions 
    { 
     public static void Set<T>(this Array array, T defaultValue) 
     { 
      int[] indicies = new int[array.Rank]; 

      SetDimension<T>(array, indicies, 0, defaultValue); 
     } 

     private static void SetDimension<T>(Array array, int[] indicies, int dimension, T defaultValue) 
     { 
      for (int i = 0; i <= array.GetUpperBound(dimension); i++) 
      { 
       indicies[dimension] = i; 

       if (dimension < array.Rank - 1) 
        SetDimension<T>(array, indicies, dimension + 1, defaultValue); 
       else 
        array.SetValue(defaultValue, indicies); 
      } 
     } 
    } 

使用像這樣:

int[, ,] test1 = new int[3, 4, 5]; 
test1.Set(1); 

int[,] test2 = new int[3, 4]; 
test2.Set(1); 

int[] test3 = new int[3]; 
test3.Set(1); 
+0

謝謝,是的,確切地說,那是我的想法。它看起來相當複雜,但似乎沒有真正的.net內置解決方案來解決這個問題。 – 2012-02-29 13:54:41

2

我會強烈建議使用一維數組,和值依次映射。您需要將i,j,k,...的零件轉換爲正確的數組索引,這是通過下面的Que()函數完成的,它是泛型數組類SeqArray<T>的一部分。

// Test code first 
class Program 
{ 
    static void Main(string[] args) 
    { 
     /* 3 pages, of a 4x2 matrix 
     * 
     *   |16 17| 
     *  | 8 9|19| 
     * | 0 1|11|21| 
     * | 2 3|13|23| 
     * | 4 5|15| 
     * | 6 7| 
     * 
     * shown above are the sequential indeces for a rank 3 array 
     */ 
     SeqArray<double> arr = new SeqArray<double>(3, 4, 2); 
     // Initialize values to squential index "num" 
     int num = 0; 
     for (int i = 0; i < 3; i++) 
     { 
      for (int j = 0; j < 4; j++) 
      { 
       for (int k = 0; k < 2; k++) 
       { 
        arr[i, j, k] = num++; 
       } 
      } 
     } 
     // Check that the array values correspond to the index sequence 
     num = 0; 
     for (int i = 0; i < 3 * 4 * 2; i++) 
     { 
      Trace.Assert(arr.InnerArray[i] == num++); 
     } 

     // Initialize with value=π 
     arr = new SeqArray<double>(Math.PI, 4, 5, 6); 
    } 

} 

public class SeqArray<T> 
{ 
    T[] values; 
    int[] lengths; 

    public SeqArray(params int[] lengths) 
    { 
     this.lengths = lengths; 
     int N = 1; 
     for (int i = 0; i < lengths.Length; i++) 
     { 
      N *= lengths[i]; 
     } 
     values = new T[N]; 
    } 
    public SeqArray(T value, params int[] lengths) : this(lengths) 
    { 
     for (int i = 0; i < values.Length; i++) 
     { 
      values[i] = value; 
     }    
    } 
    public int[] Lengths { get { return lengths; } } 
    public int Size { get { return values.Length; } } 
    internal T[] InnerArray { get { return values; } } 
    public int Que(params int[] indeces) 
    { 
     // Check if indeces are omited like arr[4] instead of arr[4,0,0] 
     if (indeces.Length < lengths.Length) 
     { 
      // Make a new index array padded with zeros 
      int[] temp = new int[lengths.Length]; 
      indeces.CopyTo(temp, 0); 
      indeces = temp; 
     } 
     // Count the elements for indeces 
     int k = 0; 
     for (int i = 0; i < indeces.Length; i++) 
     { 
      k = lengths[i] * k + indeces[i]; 
     } 
     return k; 
    } 

    public T this[params int[] indeces] 
    { 
     get { return values[Que(indeces)]; } 
     set { values[Que(indeces)] = value; } 
    } 
} 
+0

不錯的解決方案,在性能方面看起來很有希望! – 2012-02-29 15:00:38

+0

您必須爲不同的數字類型創建子類才能使用'+','-'運算符重載。爲了編碼矩陣乘法將是一件小事,但是可行。 – ja72 2012-02-29 15:35:03

1

這裏是一個非遞歸版本的替代者個人意見,上述安迪·霍爾特:

public static void SetAll<T>(this Array array, T value) 
    { 
     var sizes = new int[array.Rank]; 

     sizes[array.Rank - 1] = 1; 
     for (var d = array.Rank - 2; d >= 0; d--) 
     { 
      sizes[d] = array.GetLength(d + 1)*sizes[d + 1]; 
     } 

     for (var i = 0; i < array.Length; i++) 
     { 
      var remainder = i; 
      var index = new int[array.Rank]; 
      for (var d = 0; d < array.Rank && remainder > 0; d++) 
      { 
       index[d] = remainder/sizes[d]; 
       remainder -= index[d]*sizes[d]; 
      } 
      array.SetValue(value, index); 
     } 
    }