C# n维阵列
我想创建一个n维的双精度数组。在编译时,维数n是未知的 我最终将数组定义为一个字典,其中键是一个对应于不同轴的整数数组(因此在三维数组中,我将提供[5,2,3],以获得数组中(5,2,3)处的双精度 但是,我还需要用从(0,0,…0)到(m1,m2,…mn)的双精度数字填充字典,其中m1到mn是每个轴的长度 我最初的想法是为循环创建嵌套,但我仍然不知道需要多少(每个维度1个),所以我不能在编译时这样做C# n维阵列,c#,arrays,multidimensional-array,C#,Arrays,Multidimensional Array,我想创建一个n维的双精度数组。在编译时,维数n是未知的 我最终将数组定义为一个字典,其中键是一个对应于不同轴的整数数组(因此在三维数组中,我将提供[5,2,3],以获得数组中(5,2,3)处的双精度 但是,我还需要用从(0,0,…0)到(m1,m2,…mn)的双精度数字填充字典,其中m1到mn是每个轴的长度 我最初的想法是为循环创建嵌套,但我仍然不知道需要多少(每个维度1个),所以我不能在编译时这样做 我希望我已经以一种可以理解的方式阐述了这个问题,但请随意让我详细说明各个部分。为什么不使用多维
我希望我已经以一种可以理解的方式阐述了这个问题,但请随意让我详细说明各个部分。为什么不使用多维数组:
double[,]array=new double[a,b,c]
?所有数组元素都会自动初始化为0.0
或者,您可以使用锯齿状数组double[][]
,但每个子数组都需要在for
循环中初始化:
int a, b, c;
double[][][] array = new double[a][][];
for (int i=0; i<a; i++) {
double[i] = new double[b][];
for (int j=0; j<b; j++) {
double[i][j] = new double[c];
}
}
inta、b、c;
双精度[][]阵列=新的双精度[a][];
对于(int i=0;i要创建n维数组,可以使用以下方法:
要填充数组,可以使用Rank
属性和GetLength
方法返回当前维度的长度,使用两个嵌套for循环执行O(n^m)算法(警告-未测试):
对此问题的快速跟进:
我们成功地使用了Array.CreateInstance方法,但正如有人预测的那样,它效率相当低,并且还造成了可读性问题
相反,我们开发了一种方法,将n维数组转换为一维(法线)数组
公共静态int ndtoone(int[]索引,int[]长度)
{
int ID=0;
for(int i=0;i=0;i--)
{
int offset=1;
对于(int j=0;j
这本质上是一个将笛卡尔坐标转换为单个整数再转换回来的推广
我们的测试还没有正式化,所以我们获得的任何加速都是轶事,但对于我的机器来说,它提供了大约30-50%的加速,这取决于样本大小,并且代码的可读性大大提高
希望这能帮助任何偶然发现这个问题的人。使用此方法,您可以创建任意类型的n维锯齿阵列
public static Array CreateJaggedArray<T>(params int[] lengths)
{
if(lengths.Length < 1)
throw new ArgumentOutOfRangeException(nameof(lengths));
void Populate(Array array, int index)
{
for (int i = 0; i < array.Length; i++)
{
Array element = (Array)Activator.CreateInstance(array.GetType().GetElementType(), lengths[index]);
array.SetValue(element, i);
if (index + 1 < lengths.Length)
Populate(element, index + 1);
}
}
Type retType = typeof(T);
for (var i = 0; i < lengths.Length; i++)
retType = retType.MakeArrayType();
Array ret = (Array)Activator.CreateInstance(retType, lengths[0]);
if (lengths.Length > 1)
Populate(ret, 1);
return ret;
}
公共静态数组CreateJaggedArray(参数int[]长度)
{
如果(长度。长度<1)
抛出新ArgumentOutOfRangeException(nameof(length));
无效填充(数组、整数索引)
{
for(int i=0;i1)
填充(ret,1);
返回ret;
}
因为我不知道编译时的维度数。抱歉,如果(5,2,3)示例让您感到困惑,那么它可能是(5,3,2,8,7,6,32)。:)它将用于阶乘马尔可夫随机场计算,其中我们有n个层,每个层中有m个段。然后,我们希望为每个观察值建立一个概率矩阵,或者在连续值的情况下,为每个观察值建立两个矩阵,用于均值和方差。
private bool Increment(Array array, int[] idxs, int dim) {
if (dim >= array.Rank) return false;
if (++idxs[idxs.Length-dim-1] == array.GetLength(dim)) {
idxs[idxs.Length-dim-1] = 0;
return Increment(array, idxs, dim+1);
}
return true;
}
Array array = Array.CreateInstance(typeof(double), ...);
int[] idxs = new int[array.Rank];
while (Increment(array, idxs, 0)) {
array.SetValue(1d, idxs);
}
public static int NDToOneD(int[] indices, int[] lengths)
{
int ID = 0;
for (int i = 0; i < indices.Length; i++)
{
int offset = 1;
for (int j = 0; j < i; j++)
{
offset *= lengths[j];
}
ID += indices[i] * offset;
}
return ID;
}
1DtoND(int[] indices, int[] arrayLengths)
{
int[] indices = new int[lengths.Length];
for (int i = lengths.Length - 1; i >= 0; i--)
{
int offset = 1;
for (int j = 0; j < i; j++)
{
offset *= lengths[j];
}
int remainder = ID % offset;
indices[i] = (ID - remainder) / offset;
ID = remainder;
}
return indices;
}
public static Array CreateJaggedArray<T>(params int[] lengths)
{
if(lengths.Length < 1)
throw new ArgumentOutOfRangeException(nameof(lengths));
void Populate(Array array, int index)
{
for (int i = 0; i < array.Length; i++)
{
Array element = (Array)Activator.CreateInstance(array.GetType().GetElementType(), lengths[index]);
array.SetValue(element, i);
if (index + 1 < lengths.Length)
Populate(element, index + 1);
}
}
Type retType = typeof(T);
for (var i = 0; i < lengths.Length; i++)
retType = retType.MakeArrayType();
Array ret = (Array)Activator.CreateInstance(retType, lengths[0]);
if (lengths.Length > 1)
Populate(ret, 1);
return ret;
}