C# 多维数组的泛型初始化

C# 多维数组的泛型初始化,c#,multidimensional-array,C#,Multidimensional Array,我有一个多维数组,我想以简单快速的方式初始化它: double[,,] arr = new double[4,5,6]; // doesn't work by design foreach(double d in arr) d = ... ; // my initialization value 这显然行不通。但我希望有一个通用函数,用于将所有数组值设置为choosen默认值。对于自己的类,我可以编写一个特殊的构造函数,但对于值类型,我没有真正的想法。使用C++,我可以用线性方式访问所有

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

double[,,] arr = new double[4,5,6];
// doesn't work by design
foreach(double d in arr)
   d = ... ; // my initialization value
这显然行不通。但我希望有一个通用函数,用于将所有数组值设置为choosen默认值。对于自己的类,我可以编写一个特殊的构造函数,但对于值类型,我没有真正的想法。使用C++,我可以用线性方式访问所有项,其中一个用于循环,但是在C语言中,我认为我必须使用循环,因为我有维度。目前我没有更好的解决方案(或者我正在使用不安全的代码和指针算法,这可能会奏效)


有没有更优雅的方法

不太确定它是否是您想要的,但是下面的扩展方法将允许您初始化数组中的每个值,而不考虑维数

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

我强烈建议使用1D数组,并按顺序映射值。您需要将索引
i
j
k
转换为正确的数组索引,这是通过下面的
Que()
函数完成的,它是泛型数组类
SeqArray
的一部分

//首先测试代码
班级计划
{
静态void Main(字符串[]参数)
{
/*3页,4x2矩阵
* 
*         |16 17|
*      | 8  9|19|
*   | 0  1|11|21|
*   | 2  3|13|23|
*   | 4  5|15|
*   | 6  7|
*   
*上面显示的是秩3数组的顺序索引
*/
SeqArray arr=新的SeqArray(3,4,2);
//将值初始化为压缩索引“num”
int num=0;
对于(int i=0;i<3;i++)
{
对于(int j=0;j<4;j++)
{
对于(int k=0;k<2;k++)
{
arr[i,j,k]=num++;
}
}
}
//检查数组值是否对应于索引序列
num=0;
对于(int i=0;i<3*4*2;i++)
{
Assert(arr.InnerArray[i]==num++);
}
//使用值=π初始化
arr=新的SeqArray(Math.PI,4,5,6);
}
}
公共类数组
{
T[]值;
int[]长度;
公共SeqArray(参数int[]长度)
{
这个。长度=长度;
int N=1;
for(int i=0;i
这里有一个非递归版本,可以替代上面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);
        }
    }
publicstaticvoidsetall(此数组,T值)
{
var size=newint[array.Rank];
大小[array.Rank-1]=1;
对于(vard=array.Rank-2;d>=0;d--)
{
大小[d]=array.GetLength(d+1)*大小[d+1];
}
for(var i=0;i0;d++)
{
索引[d]=余数/大小[d];
余数-=索引[d]*大小[d];
}
数组.SetValue(值,索引);
}
}

如果您关心速度,请不要使用多维数组。它们在.NET中的速度非常慢(无论如何,与一维数组相比)。即使是锯齿状数组也更快,尽管存在指针追踪。这里最简单、最快的方法是将其设置为一维,然后自己进行索引计算。这与某种程度上相关,并且发现它很有趣:感谢您的评论,速度在我当前的应用程序中不是一个实际问题,但我更喜欢一个干净的语法。您所说的“自己的类”与“值类型”是什么意思?您可以为
结构编写自己的构造函数,该结构也是一种值类型。对不起,如果我误解了。嗯,是的,但我指的是基本类型,如double、int等。谢谢,是的,没错,这是我的想法。它看起来相当复杂,但似乎没有真正的.net内置解决方案来解决这个问题。为了使用
+
-
运算符重载,您必须为不同的数字类型创建子类。对矩阵乘法进行编码虽然工作量不大,但却是可行的。
// 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; }
    }
}
    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);
        }
    }