Индексирование в массивы произвольного ранга в C # - PullRequest
5 голосов
/ 04 августа 2010

Мне нужно перебрать массив произвольного ранга.Это для чтения и записи, поэтому GetEnumerator не будет работать.

Array.SetValue(object, int) не работает на многомерных массивах.Array.SetValue(object, params int[]) потребует чрезмерной арифметики для итерации по многомерному пространству.Это также потребовало бы динамического вызова для обхода части params подписи.

Я испытываю желание закрепить массив и выполнить итерацию по нему с указателем, но я не могу найти документацию, которая говоритчто многомерные массивы гарантированно будут смежными.Если у них есть отступ в конце измерения, это не сработает.Я также предпочел бы избежать небезопасного кода.

Существует ли простой способ последовательной адресации многомерного массива с использованием только одного индекса?

Ответы [ 3 ]

5 голосов
/ 04 августа 2010

Многомерные массивы гарантированно будут смежными. От 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
1 голос
/ 04 августа 2010

Вы можете использовать свойство / метод 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;
}

.. и используйте его так:

for (var i = 0; i < array.Length; i++)
{
    var indices = Indices(array, i);
    array.SetValue(i, indices);
    var val = array.GetValue(indices);
}
0 голосов
/ 04 августа 2010

Возможно, вы могли бы объединить их всех в одну временную коллекцию и просто повторить.

...