Как изменить размер многомерного (2D) массива в C #?

Я пробовал следующее, но он просто возвращает испорченный массив.

    T[,] ResizeArray<T>(T[,] original, int rows, int cols)
    {
        var newArray = new T[rows,cols];
        Array.Copy(original, newArray, original.Length);
        return newArray;
    }
29
задан Manuel 27 March 2012 в 15:07
поделиться

3 ответа

Спасибо, Томас, ваше объяснение было очень полезным, но реализованное вами решение слишком медленное. Я изменил его, чтобы использовать Array.Copy.

    void ResizeArray<T>(ref T[,] original, int newCoNum, int newRoNum)
    {
        var newArray = new T[newCoNum,newRoNum];
        int columnCount = original.GetLength(1);
        int columnCount2 = newRoNum;
        int columns = original.GetUpperBound(0);
        for (int co = 0; co <= columns; co++)
            Array.Copy(original, co * columnCount, newArray, co * columnCount2, columnCount);
        original = newArray;
    }

Здесь я предполагаю, что строк больше, чем столбцов, поэтому я структурировал массив как [столбцы, строки]. Таким образом, я использую Array.Copy для всего столбца за один снимок (намного быстрее, чем одна ячейка за раз).

Он работает только для увеличения размера массива, но его также можно изменить, чтобы уменьшить размер.

9
ответ дан 28 November 2019 в 01:20
поделиться

Большинство методов в классе массива работают только с одномерными массивами, поэтому вы должны выполнить копирование вручную:

T[,] ResizeArray<T>(T[,] original, int rows, int cols)
{
    var newArray = new T[rows,cols];
    int minRows = Math.Min(rows, original.GetLength(0));
    int minCols = Math.Min(cols, original.GetLength(1));
    for(int i = 0; i < minRows; i++)
        for(int j = 0; j < minCols; j++)
           newArray[i, j] = original[i, j];
    return newArray;
}

Чтобы понять, почему это не работает с Array.Copy, вам нужно рассмотреть расположение многомерного массива в памяти. Элементы массива не на самом деле хранятся в виде двумерного массива, они хранятся непрерывно, строка за строкой. Итак, этот массив:

{ { 1, 2, 3 },
  { 4, 5, 6 } }

на самом деле устроен в памяти так: { 1, 2, 3, 4, 5, 6 }

Теперь предположим, что вы хотите добавить еще одну строку и еще один столбец, чтобы массив выглядел вот так:

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

Теперь расположение в памяти будет следующим: { 1, 2, 3, 0, 4, 5, 6, 0, 0, 0, 0, 0 }

Но Array.Copy рассматривает все массивы как одномерные. MSDN говорит:

При копировании между многомерными массивами массив ведет себя как длинный одномерный массив, в котором строки (или столбцы) концептуально заложены в конец

Поэтому, когда вы пытаетесь скопировать исходный массив в новый, он просто копирует одну ячейку памяти в другую, что дает в одномерном представлении:

{ 1, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0 }.

Если вы преобразуете это в двумерное представление, вы получите следующее:

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

Вот почему вы получаете испорченный массив ... Обратите внимание, что это будет работать свойство, если вы изменилось количество строк, но не количество столбцов.

35
ответ дан 28 November 2019 в 01:20
поделиться

Это объединяет ответы Томаса и Мануэля и обеспечивает выигрыш в производительности Array.Copy и возможность увеличивать и уменьшать размер массива.

    protected T[,] ResizeArray<T>(T[,] original, int x, int y)
    {
        T[,] newArray = new T[x, y];
        int minX = Math.Min(original.GetLength(0), newArray.GetLength(0));
        int minY = Math.Min(original.GetLength(1), newArray.GetLength(1));

        for (int i = 0; i < minY; ++i)
            Array.Copy(original, i * original.GetLength(0), newArray, i * newArray.GetLength(0), minX);

        return newArray;
    }

Обратите внимание , что оси x и y вашего массива соответствуют вашей собственной реализации, и вам может потребоваться переключить 0 и 1 для достижения желаемого эффекта.

13
ответ дан 28 November 2019 в 01:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: