You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何用Index与Range实现交错数组及Matrix类的切片功能

交错数组链式切片不符合预期的根本原因

C#中的交错数组是「数组的数组」,本质是一维数组,每一个元素又是另一个一维数组,不存在原生的多维切片语义。链式索引的求值逻辑是从左到右依次执行,而非把两个索引/范围合并为多维切片操作:

  • 执行A[..][0]时,第一步A[..]会先对第一层的行数组做全量切片,返回和原数组完全一致的3行float[][],第二步再对这个返回的行数组取第0个元素,也就是原数组的第0行,结果自然和A[0][..]完全一致。
  • 执行A[0..2][0..2]时,第一步A[0..2]先切取前2行的数组,第二步0..2是对这个包含2个元素的行数组做切片,返回的还是这2行,每一行本身的元素没有被切片,所以每行仍然保留3个元素。

你原来编写的Matrix索引器错误就是直接沿用了交错数组的链式切片逻辑,没有处理列维度的切片操作,因此结果不符合预期。

自定义Matrix类切片实现方案

你可以直接复用C#的Index、Range语法能力,自行在索引器中实现多维度切片逻辑,修改后的索引器代码如下:

public class Matrix 
{
    readonly double[][] Elements;

    /// <summary>Reference a single element</summary>
    public ref double this[Index row, Index column] 
        => ref Elements[row][column];

    /// <summary>Extract a sub-matrix</summary>
    public double[][] this[Range rows, Range columns]
    {
        get
        {
            var selectedRows = Elements[rows];
            var result = new double[selectedRows.Length][];
            for (int i = 0; i < selectedRows.Length; i++)
            {
                result[i] = selectedRows[i][columns];
            }
            return result;
        }
    }

    /// <summary>Extract a row sub-vector</summary>
    public double[] this[Index row, Range columns]
        => Elements[row][columns];

    /// <summary>Extract a column sub-vector</summary>
    public double[] this[Range rows, Index column]
    {
        get
        {
            var selectedRows = Elements[rows];
            var result = new double[selectedRows.Length];
            for (int i = 0; i < selectedRows.Length; i++)
            {
                result[i] = selectedRows[i][column];
            }
            return result;
        }
    }
}

修改后即可实现你预期的Fortran风格切片效果,比如matrix[0..2, 0..2]就会返回前两行前两列的子矩阵,matrix[.., 0]会返回第一列的所有元素。

^0的设计逻辑说明

这个设计不存在语义不一致的问题,和C# Range的左闭右开规则是完全统一的:

  • Index类型的^n语义是「从数组末尾向前数第n个位置的边界」,^1是最后一个元素的前边界,对应最后一个元素;^0是最后一个元素的后边界,对应数组的长度值。
  • Range类型遵循左闭右开规则[起始边界, 结束边界),包含起始边界对应的元素,不包含结束边界对应的元素。如果需要包含最后一个元素,结束边界就需要设为最后一个元素的后边界也就是^0,这样就能把最后一个元素纳入范围。

你觉得容易混淆主要是因为Fortran的切片默认是左闭右闭规则,和C#的设计不同,适应规则后就不会有问题。

内容的提问来源于stack exchange,提问作者John Alexiou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 05:54:03