多维数组的通用初始化

时间:2012-02-29 09:46:01

标签: c# multidimensional-array

我有一个多维数组,我想以简单快速的方式初始化:

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

这显然不起作用。但是我希望有一个通用函数来将所有数组值设置为选择的默认值。使用自己的类,我可以编写一个特殊的构造函数,但是对于值类型我没有真正的想法。使用C ++,我可以使用一个for循环以线性方式访问所有项目,但在C#中我认为我将使用尽可能多的循环,因为我有维度。我目前还没有更好的解决方案(或者我使用的是不安全的代码和指针算法,这可能会有效。)。

这样做有更优雅的方式吗?

3 个答案:

答案 0 :(得分: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);

答案 1 :(得分:2)

我强烈建议使用1D数组,并按顺序映射值。您需要将indeces ijk...转换为正确的数组索引,该索引使用下面的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; }
    }
}

答案 2 :(得分:1)

以下是Andy Holt发布的非递归版本替代版本:

    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);
        }
    }