C# C语言中任意秩数组的索引#
我需要迭代任意秩的数组。这是用于读取和写入的,因此C# C语言中任意秩数组的索引#,c#,arrays,iteration,padding,pinning,C#,Arrays,Iteration,Padding,Pinning,我需要迭代任意秩的数组。这是用于读取和写入的,因此GetEnumerator将不起作用 Array.SetValue(object,int)不适用于多维数组。 Array.SetValue(object,params int[])在多维空间中迭代时需要过多的算术运算。它还需要动态调用来绕过签名的params部分 我试图固定数组并用指针对其进行迭代,但我找不到任何文档说明多维数组保证是连续的。如果他们在维度的末尾有填充,那么这将不起作用。我还希望避免使用不安全的代码 是否有一种简单的方法可以只使用
GetEnumerator
将不起作用
Array.SetValue(object,int)
不适用于多维数组。
Array.SetValue(object,params int[])
在多维空间中迭代时需要过多的算术运算。它还需要动态调用来绕过签名的params
部分
我试图固定数组并用指针对其进行迭代,但我找不到任何文档说明多维数组保证是连续的。如果他们在维度的末尾有填充,那么这将不起作用。我还希望避免使用不安全的代码
是否有一种简单的方法可以只使用一个索引来顺序寻址多维数组?也许您可以将它们全部加入到一个临时集合中,然后只需迭代即可。多维数组保证是连续的。从ECMA-335: 阵列元素应按行主顺序排列在阵列对象内(即,与最右边的阵列维度相关的元素应从最低索引到最高索引连续排列) 所以这是可行的:
int[,,,] array = new int[10, 10, 10, 10];
fixed (int* ptr = array)
{
ptr[10] = 42;
}
int result = array[0, 0, 1, 0]; // == 42
您可以使用
Rank
和GetUpperBound
属性/方法创建索引数组,您可以将其传递给数组的SetValue
和GetValue
方法:
int[] Indices(Array a, int idx)
{
var indices = new int[a.Rank];
for (var i = 0; i < a.Rank; i++)
{
var div = 1;
for (var j = i + 1; j < a.Rank; j++)
{
div *= a.GetLength(j);
}
indices[i] = a.GetLowerBound(i) + idx / div % a.GetLength(i);
}
return indices;
}
int[]索引(数组a,int idx)
{
var指数=新整数[a.Rank];
对于(变量i=0;i
…并像这样使用它:
for (var i = 0; i < array.Length; i++)
{
var indices = Indices(array, i);
array.SetValue(i, indices);
var val = array.GetValue(indices);
}
for(变量i=0;i
我认为使用“不安全”代码没有错误。当您真正知道自己在做什么时,使用指针是安全的,而且这是一个可行且有效的解决方案。顺便说一句,在需要params int[]
的地方传递int[]
是完全有效的。@dtb,您似乎在两个语法点上都是正确的。我从来不知道可以直接将数组传递给params数组参数。@Mikael Svenson,我同意不安全代码不必担心,但我也认为如果有同等的安全解决方案,应该避免这种情况。谢谢,这正是我所寻找的,并给了我一个很好的回退实现。顺便说一句,我认为您的代码被“int*ptr=array”阻塞了,但这个想法是正确的。@Kennet Belenky:我刚刚仔细检查了一下,代码运行得很好。当然,如果您想避免不安全代码,涉及不安全代码的解决方案是没有帮助的,但我担心没有其他解决方案不会带来很多(不必要的)开销(例如递归地遍历所有维度)。。。。然而,结果表明,仅当数组包含基元值类型时,固定才起作用。我在最初的问题中没有提到这一点,但我试图解决的数组也有一个任意ElementType,可能包含结构、引用类型或装箱值类型。我想我必须求助于使用索引数组。很简单,我将使用GetEnumerator来处理数组中的所有内容。问题是我还必须在数组中的不同点上写入,GetEnumerator将因此失败。是的,这将是我所说的过度算术。您还需要使用Array.GetLowerBound,而不仅仅是Array.GetUpperBound。@kennet实际上,我们不需要Array.GetUpperBound
,只看到了Array.GetLength
方法:)