Как мне получить ссылку на одно измерение многомерного массива в C #?

StackOverflow https://stackoverflow.com/questions/3964299

Вопрос

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

После создания массива я хотел бы работать всего 1 измерения этого массива. Возможно, передайте ссылку на метод.

Вот вымышленный пример:

// Create a table 3x3 table.
int[,] DistanceTable = new int[3, 3];
DistanceTable[0, 0] = 0;
DistanceTable[1, 1] = 0;
DistanceTable[2, 2] = 0;

DistanceTable[0, 1] = 10;
DistanceTable[0, 2] = 40;

DistanceTable[1, 0] = 10;
DistanceTable[1, 2] = 25;

DistanceTable[2, 0] = 40;
DistanceTable[2, 1] = 25;

// Why can't I do this?
int[] twos = DistanceTable[2];

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

Можно ли сделать это? Если не почему?

Спасибо

Это было полезно?

Решение

Нет. Многомерные массивы отличаются от язваных массивов в том, что они хранятся последовательно, в одном блоке памяти, используя Строка - основной заказ.

Из-за этого вытащивание одного «колонна» данных требует пропуска, чтобы вытащить это.

Языванные массивы, с другой стороны, являются массивом ссылок на второй массив. Это облегчает вытащить индивидуальные «массивы» из язванного массива.

Но мне не нужен Jaggedarray, потому что мой многомерный массив всегда имеет одинаковое количество столбцов для каждой строки.

Языванные массивы в .NET имеют несколько огромных оптимизаций производительности. Они часто превосходят многомерные массивы. Вот почему большая часть процедуры анализа кода предложит преобразование в зазубренный массив из двухмерного массива. Стоит учитывать это, даже если вы не «нуждаетесь».

Другие советы

Это невозможно; Многомерные массивы не работают так.

В общем, вы всегда должны использовать зазубренные массивы; Они быстрее.
(Джиттер будет генерировать инструкции доступа к необработанным памятью вместо вызовов методов)

Существует только один объект массива с многомерным массивом, тогда как aa jagged массив - это гнездование нескольких отчетливый объекты массива. Не существует 1-1 матча или метод извлечения (который не связан с использованием обертки).

Извините, это действительно должно быть комментарий к Как мне получить ссылку на одно измерение многомерного массива в C #? Но мне еще не разрешено комментировать ..

Во всяком случае, причина того, почему производительность лучше с зазубренным массивом легко понять после некоторого объяснения: давайте рассмотрим многомерный массив:

{{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}

В памяти он хранится что-то вроде этого: {0, 1, 2, 3, 4, 5, 6, 7, 8}.

Теперь предположим, что вы хотите получить доступ [0, 0], где в памяти мы собираемся прочитать? Мы должны рассчитать адрес: y * 3 + x => 0 * 3 + 0 => 0. После этого мы можем продолжать и сделать фактическую прочитанную. Если мы хотим прочитать всю строку, мы должны сделать эту математику снова и снова.

Вместо этого посмотрите на зазубренный массив, в память оно хранится что-то вроде этого:

A: {0, 1, 2} B: {3, 4, 5} C: {6, 7, 8} {Ref: a, ref: b, ref: c}

Предположим, мы хотим получить доступ [0] [0], где в памяти мы будем читать? Во-первых, давайте получим ссылку на массив [0]. А затем получить содержание клетки [0]. Сделанный. Если мы хотим прочитать всю линию, нам нужно только увеличить указатель на один.

Если мы собираемся итереть через весь «массив» вместо одного ряда, это все еще такая же выгода для зазубренных массивов.

Хотя есть одно исключение: итеративные колонны. Это действительно плохо для зазубренных массивов, так как мы собираемся сделать относительную дорогую прочитать память для каждого доступа. Нехорошо.

Если вы чувствуете, что это проблема, останется один метод: одномерный массив! В этом случае мы используем теорию для многомерного массива (y * rowlength + x) и используйте некоторую действительно простую математику; Чтобы итереть ряд: просто увеличивайте на один, чтобы повторить столбец: просто приращение на RowLength.

Вы можете сделать метод расширения в вашем разъемы вашего словаря, который позволяет вам указать строку?

public static class IntArrayExt
{
    public static int[] Row(this int[,] array, int row)
    {
        int[] newArray = new int[3];
        for (int i = 0; i < array.Length; i++)
        {
            newArray[i] = array[row, i];
        }
        return newArray;
    }
}

int[,] distanceTable = new int[3, 3];
distanceTable[0, 0] = 0;
distanceTable[1, 1] = 0;
distanceTable[2, 2] = 0;

distanceTable[0, 1] = 10;
distanceTable[0, 2] = 40;

distanceTable[1, 0] = 10;
distanceTable[1, 2] = 25;

distanceTable[2, 0] = 40;
distanceTable[2, 1] = 25;

int[] twos = distanceTable.Row(2);

Вы можете сделать другой метод расширения, если хотите получить столбец.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top