具有非零下限的二维数组的子数组

Posted

技术标签:

【中文标题】具有非零下限的二维数组的子数组【英文标题】:SubArray of a 2d array with non-zero lower bounds 【发布时间】:2021-02-04 18:27:24 【问题描述】:

扩展名:

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 result;

适用于GetLowerBound(0)GetLowerBound(1) 等于0 的二维数组。例如如果

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是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);

前面代码的最后一行sn -p会在该行的SubArray扩展函数中触发异常

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

对于row 等于零。

我了解二维数组 arr1(具有从零开始的索引)在内存中的布局,但不了解二维数组 arr2(具有非从零开始的索引)在内存中的布局方式,因此我使用Array.Copy 在这种情况下肯定是错误的,但我不明白为什么。

【问题讨论】:

【参考方案1】:

您没有正确计算total_colsfrom_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 result;

total_cols 是显而易见的;至于from_index,我找不到任何相关文档,但似乎Array.Copy 中的sourceIndex 是从sourceArray.GetLowerBound(0) 开始计数,而不是从零开始计数,鉴于该指数不断增长,这一点不一定立即显而易见行和列。

【讨论】:

确实有效。我试图制作SubArray,不仅让它返回一个从零开始的索引数组,而且(提供bool rebase)一个数组,其行从索引row_min开始,列从索引col_min开始(通过用适当的T[,] result = (T[,]) Array.CreateInstance(typeof(T), new int[] num_rows, num_cols, new int[] rebase ? 0 : row_min, rebase ? 0 : col_min ); 替换new 行)。在这种情况下,total_colsfrom_index 不会更改,但 to_index 会更改,并且如果 rebasefalse 则应该等于 col_min 但它似乎不起作用 @11house should be equal to col_min - 反过来:int to_index = rebase ? 0 : row_min;。正如问题中所述,Array.Copy 从sourceArray.GetLowerBound(0) 开始计数,即row_min

以上是关于具有非零下限的二维数组的子数组的主要内容,如果未能解决你的问题,请参考以下文章

获取具有特定键/值对的二维数组中的子数组

怎么用java取出出指定条件二维数组的子数组

从巨大的二维结构数组中创建结构的子数组

返回一个二维整形数组的子数组的最大和

创建线性二维数组的子数组

比较 Ruby 中二维数组的子数组,并显示结果数组与现有和遗漏的项目