[英]n-dimensional Array
我想創建一個n維的雙精度數組。 在編譯時,維數n的數量是未知的。
我最后將數組定義為字典,鍵是一個對應於不同軸的int數組(所以在三維數組中,我提供[5,2,3]得到雙精度(5 ,2,3)在數組中。
但是,我還需要使用從(0,0,... 0)到(m1,m2,... mn)的雙精度填充字典,其中m1到mn是每個軸的長度。
我最初的想法是創建嵌套的for循環,但由於我仍然不知道我需要多少(每個維度1個),所以我無法在編譯時執行此操作。
我希望我以一種可以理解的方式提出問題,但請隨時讓我詳細說明部分內容。
要創建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);
}
快速跟進此事:
我們成功使用了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%的加速,具體取決於樣本大小,並且代碼的可讀性大大提高了。
希望這可以幫助任何偶然發現這個問題的人。
你為什么不使用多維數組: 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];
}
}
編輯:沒有意識到維度的數量是運行時。 上面添加了另一個答案
使用此方法,您可以創建任何類型的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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.