连续填充未知维度的数组

时间:2016-03-07 15:03:11

标签: c# arrays algorithm performance multidimensional-array

我有Array未知维度。例如。可能是object[]object[,]object[,,,]

我想按顺序填写(例如[2,2]这个顺序:0,0; ​​0,1,1,0; 1,1):

Array arr = ... // input array
for (int i = 0; i < arr.Length; i++)
{
     arr.SetValue(stream.ReadNextObject(), ???); // convert i -> int[] indexes
}

我知道i的对话可以通过%运算符完成,但很难想象多维度的精确算法。二维只有一个答案:Converting index of one dimensional array into two dimensional array i. e. row and column

我可以使用Stack<int>在遍历数组时存储索引,但似乎%会更有效(我真的需要关心这里的性能)。但我不确定Stack<T> vs %

2 个答案:

答案 0 :(得分:4)

以下是我认为您正在寻找的算法

public static int[] SingleIndexToMulti(int index, int[] dimentionSizes)
{
    var result = new int[dimentionSizes.Length];
    for (int i = dimentionSizes.Length - 1; i >=0; i--)
    {
        result[i] = index % dimentionSizes[i];
        index = index / dimentionSizes[i];
    }

    return result;
}

你会像这样使用它

Array myArray = Whatever();
int[] dimensionSizes = new int[myArray.Rank];
for(int i =0; i < myArray.Rank; i++)
    dimensionsSizes[i] = myArray.GetLength(i);
for (int i = 0; i < arr.Length; i++)
{
    arr.SetValue(stream.ReadNextObject(), SingleIndexToMulti(i, dimensionSizes)); 
}

演示以下代码

for(int i=0; i < (2*3*4) ;i++)
    Console.WriteLine(string.Join(",", SingleIndexToMulti(i, new[] { 2, 3, 4 })));

可生产

  

0,0,0

     

0,0,1

     

0,0,2

     

0,0,3

     

0,1,0

     

0,1,1

     

0,1,2

     

0,1,3

     

0,2,0

     

0,2,1

     

0,2,2

     

0,2,3

     

1,0,0

     

1,0,1

     

1,0,2

     

1,0,3

     

1,1,0

     

1,1,1

     

1,1,2-

     

-1,1,3-

     

1,2,0

     

1,2,1

     

1,2,2-

     

1,2,3

答案 1 :(得分:0)

我有一个递归的解决方案:

void Fill(Array a, Stream stream)
{
    int[] indices = new int[a.Rank]; // c# should initialize this with 0s
    FillRecursive(a, indices, 0, stream)    
}
void FillRecursive(Array a, int[] indices, int rank, Stream stream)
{
    for (int idx = 0; idx < a.GetLength(rank); idx++)
    {
        indices[rank] = idx;
        if (rank == a.Rank - 1)
            a.SetValue(stream.ReadNextObject(), indices);
        else
            FillRecursive(a, indices, rank + 1, stream);
    }
}

这应该可以解决问题。我计算了各个尺寸并不断设定值。 注意 Stream是一种伪代码(我的Stream没有ReadNextObject)。

我承认我没有时间真正测试它。我将性能测量结果留给您,但我认为没有更快的替代方案。

更新:测试它,它会填充&#34;细胞&#34;按照您的预期正确顺序。我使用int[3,3,3]ReadNextValue来测试它,它返回增加的整数。结果:

[0,0,0] => 0
[0,0,1] => 1
[0,0,2] => 2
[0,1,0] => 3
[0,1,1] => 4
...
[2,2,0] => 24
[2,2,1] => 25
[2,2,2] => 26

请注意,这不仅适用于任意尺寸,也适用于各个尺寸的任意长度和不同长度。