我想创建一个n维的双精度数组。在编译时,维数n的数量是未知的。
我最终将数组定义为字典,键是一个对应于不同轴的int数组(所以在三维数组中,我提供[5,2,3]来得到双在数组中的(5,2,3)。
但是,我还需要使用从(0,0,... 0)到(m1,m2,... mn)的双精度填充字典,其中m1到mn是每个轴的长度。
我最初的想法是创建嵌套的for循环,但由于我仍然不知道我需要多少(每个维度1个),所以我无法在编译时执行此操作。
我希望我能以一种可以理解的方式提出问题,但请随时让我详细说明部分。
答案 0 :(得分:16)
要创建n维数组,可以使用Array.CreateInstance
方法:
Array array = Array.CreateInstance(typeof(double), 5, 3, 2, 8, 7, 32));
array.SetValue(0.5d, 0, 0, 0, 0, 0, 0);
double val1 = (double)array.GetValue(0, 0, 0, 0, 0, 0);
array.SetValue(1.5d, 1, 2, 1, 6, 0, 30);
double val2 = (double)array.GetValue(1, 2, 1, 6, 0, 30);
要填充数组,您可以使用Rank
属性和GetLength
方法返回当前维度的长度,使用几个嵌套for循环来执行O(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);
}
答案 1 :(得分:7)
快速跟进此事:
我们成功使用了Array.CreateInstance方法,但正如有人预测的那样,效率相当低,并且还会产生可读性问题。
相反,我们开发了一种方法,将n维数组转换为1维(正常)数组。
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;
}
这实质上是将笛卡尔坐标转换为单个整数并再次转换的概括。
我们的测试没有正式化,因此我们获得的任何加速都完全是轶事,但对于我的机器,它已经提供了大约30-50%的加速,具体取决于样本大小,并且代码的可读性已经提高了差不多。
希望这有助于任何偶然发现这个问题的人。
答案 2 :(得分:0)
为什么不使用多维数组: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];
}
}
编辑:没有意识到维度的数量是运行时。上面添加了另一个答案。
答案 3 :(得分:0)
使用此方法,您可以创建任何类型的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;
}