Как скопировать строку значений из 2D-массива в массив 1D?

Мы имеем следующий объект

int [,] oGridCells;

который используется только с фиксированным первым индексом

int iIndex = 5;
for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
{
  //Get the value from the 2D array
  iValue = oGridCells[iIndex, iLoop];

  //Do something with iValue
}

Есть ли способ в .NET преобразовать значения с фиксированным первым индексом в один размерный массив (за исключением циклов значений)?

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

Моя основная причина задать вопрос - посмотреть, можно ли это сделать и как, а не использовать его для производственного кода.

Ответы

Ответ 1

Следующий код демонстрирует копирование 16 байтов (4 интервала) из двухмерного массива в 1-мерный массив.

int[,] oGridCells = {{1, 2}, {3, 4}};
int[] oResult = new int[4];
System.Buffer.BlockCopy(oGridCells, 0, oResult, 0, 16);

Вы также можете выборочно копировать только одну строку из массива, указав правильные смещения байтов. В этом примере копируется средняя строка 3-строчного 2-мерного массива.

int[,] oGridCells = {{1, 2}, {3, 4}, {5, 6}};
int[] oResult = new int[2];
System.Buffer.BlockCopy(oGridCells, 8, oResult, 0, 8);

Ответ 2

Edit:

Я понял, что есть способ! Конечно, это, вероятно, не стоит. Используйте небезопасный код. Полный пример, показывающий оба способа, с небезопасным ниже:

public class MultiSingleUnsafe
{
    public static unsafe void Main(String[] a)
    {
    int rowCount = 6;
    int iUpperBound = 10;
    int [,] oGridCells = new int[rowCount, iUpperBound];

    int iIndex = rowCount - 2; // Pick a row.

    for(int i = 0; i < iUpperBound; i++)
    {
        oGridCells[iIndex, i] = i;
    }

    for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
    {
        //Get the value from the 2D array
        int iValue = oGridCells[iIndex, iLoop];
        Console.WriteLine("Multi-dim array access iValue: " + iValue);
        //Do something with iValue
    }

    fixed(int *lastRow = &(oGridCells[iIndex,0]))
    {   
        for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
        {
        int iValue = lastRow[iLoop];
        Console.WriteLine("Pointer access iValue: " + iValue);
        }
    }
    }
}

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

Ответ 3

Вы не можете получить ссылку на каждый массив. Однако вы можете использовать jagged array.

Ответ 4

"Но если массив был сильно манипулирован, то один размерный массив был бы более эффективным, чем многомерный массив".

Я сделал некоторое профилирование именно этим прошлым летом и был удивлен, увидев существенных различий в производительности между 2D и 1D массивом.

Я не тестировал производительность зубчатого массива.

Ответ 5

Вы можете попробовать следующее:

 int[,] twoD = new int[2,2];
 twoD[0, 0] = 1;
 twoD[0, 1] = 2;
 twoD[1, 0] = 3;
 twoD[1, 1] = 4;

 int[] result = twoD.Cast<int>().Select(c => c).ToArray();

Результатом будет целочисленный массив с данными:

1, 2, 3, 4

Ответ 6

Я был бы удивлен, если бы это было возможно: я ставлю, что oGridCells[iIndex, iLoop] - это всего лишь сокращение (внутри MSIL) для oGridCells[iIndex * iLoop], и что многомерные массивы являются синтаксическим сахаром для этого.

Чтобы ответить на ваш вопрос: Нет. Вам придется зацикливать значения.