Подмассив 2d-массива с ненулевыми нижними границами

#c# #arrays #multidimensional-array

#c# #массивы #многомерный массив

Вопрос:

Расширение :

 public static T[,] SubArray<T>(this T[,] values, int row_min, int row_max, int col_min, int col_max)
{
    int num_rows = row_max - row_min   1;
    int num_cols = col_max - col_min   1;
    T[,] result = new T[num_rows, num_cols];

    int total_cols = values.GetUpperBound(1)   1;
    int from_index = row_min * total_cols   col_min;
    int to_index = 0;
    for (int row = 0; row <= num_rows - 1; row  )
    {
        Array.Copy(values, from_index, result, to_index, num_cols);
        from_index  = total_cols;
        to_index  = num_cols;
    }

    return resu<
}
  

хорошо работает для 2D-массивов массивов, чьи GetLowerBound(0) и GetLowerBound(1) равны нулю. Например, если

 int[,] arr1 = new int[5, 4];
for (int i = 0; i < 5;   i)
{
    for (int j = 0; j < 4;   j)
    {
        arr1[i, j] = i   j;
    }
}

var arr1sub = arr1.SubArray(2, 3, 1, 3);
  

Тогда arr1sub это 2d-массив с 2 строками и 3 столбцами (оба с индексами, начинающимися с 0)

 3  4  5
5  6  7
  

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

 int[,] arr2 = (int[,])Array.CreateInstance(typeof(int), new int[] { 5, 4 }, new int[] { 3, 1 });
for (int i = arr2.GetLowerBound(0); i <= arr2.GetUpperBound(0);   i)
{
    for (int j = arr2.GetLowerBound(1); j <= arr2.GetUpperBound(1);   j)
    {
        arr2[i, j] = i - arr2.GetLowerBound(0)   j - arr2.GetLowerBound(1);
    }
}
var arr2sub = arr2.SubArray(5, 6, 2, 4);
  

последняя строка предыдущего фрагмента кода вызовет исключение в функции SubArray расширения в строке

 Array.Copy(values, from_index, result, to_index, num_cols);
  

для row равного нулю.

Я понимаю, что 2d-массив arr1 (с индексами на основе нуля) размещается в памяти, но не так, как 2d-массив arr2 (с индексами, отличными от нуля) размещается в памяти, поэтому мое использование Array.Copy должно быть неправильным в этом случае, но я не понимаю, почему.

Ответ №1:

Вы неправильно total_cols и from_index правильно вычисляете.

 public static T[,] SubArray<T>(this T[,] values, int row_min, int row_max, int col_min, int col_max)
{
    int num_rows = row_max - row_min   1;
    int num_cols = col_max - col_min   1;
    T[,] result = new T[num_rows, num_cols];

    int total_cols = values.GetLength(1);
    int from_index = (row_min - values.GetLowerBound(0)) * total_cols   (col_min - values.GetLowerBound(1))   values.GetLowerBound(0);
    int to_index = 0;
    for (int row = 0; row <= num_rows - 1; row  )
    {
        Array.Copy(values, from_index, result, to_index, num_cols);
        from_index  = total_cols;
        to_index  = num_cols;
    }

    return resu<
}
  

total_cols является очевидным; что касается from_index , я не могу найти никакой документации по этому вопросу, но может показаться, что sourceIndex in Array.Copy начинает отсчет с sourceArray.GetLowerBound(0) , а не с нуля, что не обязательно сразу очевидно, учитывая, что этот индекс продолжает расти по строкам и столбцам.

Комментарии:

1. Это действительно работает. Я попытался сделать SubArray так, чтобы он не только возвращал массив индексов на основе нуля, как это происходит сейчас, но также (при условии a bool rebase ) массив, строки которого начинаются с индекса row_min , а столбцы начинаются с индекса col_min (путем замены new строки на соответствующую T[,] result = (T[,]) Array.CreateInstance(typeof(T), new int[] {num_rows, num_cols}, new int[] { rebase ? 0 : row_min, rebase ? 0 : col_min }); ). В этом случае total_cols и from_index не изменяется, но to_index делает, и должно быть равно col_min , если rebase есть false , но, похоже, это не работает

2. @11house should be equal to col_min — все наоборот : int to_index = rebase ? 0 : row_min; . Точно так же, как указано в вопросе, массив. Копирование начинает отсчет с sourceArray.GetLowerBound(0) , что является row_min .