C# 使用C中的LINQ从2D数组(int[,])中获取切片

C# 使用C中的LINQ从2D数组(int[,])中获取切片,c#,linq,multidimensional-array,C#,Linq,Multidimensional Array,我不是C专家,也不是完全的LINQ初学者,在SO和Google中搜索了一些,但没有发现如何执行以下操作: 比如说,如果我有int[10,10]数组,我如何从中得到一个2D切片 例如,如果所述数组中的值取决于它们的位置a[2,3]=23、a[4,8]=48等,我想执行以下伪代码: int[3,3] a_slice = slicer_method(a, 3, 6, 2, 5) // or anything equivalent to this > [[ 32, 33, 34], [

我不是C专家,也不是完全的LINQ初学者,在SO和Google中搜索了一些,但没有发现如何执行以下操作:

比如说,如果我有int[10,10]数组,我如何从中得到一个2D切片

例如,如果所述数组中的值取决于它们的位置a[2,3]=23、a[4,8]=48等,我想执行以下伪代码:

int[3,3] a_slice = slicer_method(a, 3, 6, 2, 5)   // or anything equivalent to this

> [[ 32, 33, 34],
   [ 42, 43, 44],
   [ 52, 53, 54]]

它不必特别使用LINQ,但我最近遇到的每一个类似操作都使用了LINQ。

在CLR上无法做到这一点,因为它不支持数组切片的概念。你能做的最好的事情就是在模拟切片的数组上创建一个包装器类型。在CLR上无法做到这一点,因为它不支持数组切片的概念。你能做的最好的事情就是在模拟切片的数组上创建一个包装器类型。你可以这样做:

public T[,] Slice<T>(T[,] a, int x1, int y1, int x2, int y2)
{
    var result = new T[x2 - x1, y2 - y1];
    for (var i = x1; i < x2; i++)
    {
        for (var j = y1; j < y2; j++)
        {
            result[i - x1, j - y1] = a[i,j];
        }
    }
    return result;
}

您可以尝试以下方法:

public T[,] Slice<T>(T[,] a, int x1, int y1, int x2, int y2)
{
    var result = new T[x2 - x1, y2 - y1];
    for (var i = x1; i < x2; i++)
    {
        for (var j = y1; j < y2; j++)
        {
            result[i - x1, j - y1] = a[i,j];
        }
    }
    return result;
}

@JaredPar是正确的,没有内在的方法来制作切片-也就是说,您可以设计一个扩展方法来实现这一点:

public static class Ext
{
    public static T[] Slice<T>(this T[] source, int fromIdx, int toIdx)
    {
        T[] ret = new T[toIdx - fromIdx + 1];
        for(int srcIdx=fromIdx, dstIdx = 0; srcIdx <= toIdx; srcIdx++)
        {
            ret[dstIdx++] = source[srcIdx];
        }
        return ret;
    }
    public static T[,] Slice<T>(this T[,] source, int fromIdxRank0, int toIdxRank0, int fromIdxRank1, int toIdxRank1)
    {
        T[,] ret = new T[toIdxRank0 - fromIdxRank0 + 1, toIdxRank1 - fromIdxRank1 + 1];

        for(int srcIdxRank0=fromIdxRank0, dstIdxRank0 = 0; srcIdxRank0 <= toIdxRank0; srcIdxRank0++, dstIdxRank0++)
        {        
            for(int srcIdxRank1=fromIdxRank1, dstIdxRank1 = 0; srcIdxRank1 <= toIdxRank1; srcIdxRank1++, dstIdxRank1++)
            {
                ret[dstIdxRank0, dstIdxRank1] = source[srcIdxRank0, srcIdxRank1];
            }
        }
        return ret;
    }
}

@JaredPar是正确的,没有内在的方法来制作切片-也就是说,您可以设计一个扩展方法来实现这一点:

public static class Ext
{
    public static T[] Slice<T>(this T[] source, int fromIdx, int toIdx)
    {
        T[] ret = new T[toIdx - fromIdx + 1];
        for(int srcIdx=fromIdx, dstIdx = 0; srcIdx <= toIdx; srcIdx++)
        {
            ret[dstIdx++] = source[srcIdx];
        }
        return ret;
    }
    public static T[,] Slice<T>(this T[,] source, int fromIdxRank0, int toIdxRank0, int fromIdxRank1, int toIdxRank1)
    {
        T[,] ret = new T[toIdxRank0 - fromIdxRank0 + 1, toIdxRank1 - fromIdxRank1 + 1];

        for(int srcIdxRank0=fromIdxRank0, dstIdxRank0 = 0; srcIdxRank0 <= toIdxRank0; srcIdxRank0++, dstIdxRank0++)
        {        
            for(int srcIdxRank1=fromIdxRank1, dstIdxRank1 = 0; srcIdxRank1 <= toIdxRank1; srcIdxRank1++, dstIdxRank1++)
            {
                ret[dstIdxRank0, dstIdxRank1] = source[srcIdxRank0, srcIdxRank1];
            }
        }
        return ret;
    }
}


是的,我不是指实际的切片,我只是想以某种方式得到一个较小尺寸的二维数组,其中包含一个较大数组的给定内矩形的值,类似于从图像中选择一个矩形,尽管我的数据与图像无关。我对问题进行了编辑,使其不会给出我想要数组方法的想法,而是给出返回子数组的任何例程,将较大的数组作为参数。@heltonbiker只需使用提供的维度创建一个新数组,并使用双for循环复制信息。到目前为止,这将是最简单、最有效的方法。在此上下文中使用LINQ很可能会导致代码更混乱、性能更低。一般来说,它往往不能很好地处理多维数组。如果这是返回一个锯齿状数组,那么LINQ可能会很有用。谢谢您的解释!我可能会接受一些类似于你建议的双倍循环的答案。是的,我不是指实际的切片,我只是想以某种方式得到一个较小尺寸的二维数组,其中包含一个较大数组的给定内部矩形的值,类似于从图像中选择一个矩形,尽管我的数据与图像无关。我对问题进行了编辑,使其不会给出我想要数组方法的想法,而是给出返回子数组的任何例程,将较大的数组作为参数。@heltonbiker只需使用提供的维度创建一个新数组,并使用双for循环复制信息。到目前为止,这将是最简单、最有效的方法。在此上下文中使用LINQ很可能会导致代码更混乱、性能更低。一般来说,它往往不能很好地处理多维数组。如果这是返回一个锯齿状数组,那么LINQ可能会很有用。谢谢您的解释!我可能会接受一些类似于您建议的双循环的答案。为什么要添加where T:struct?这段代码中没有任何东西会妨碍类的正确性。哦,索引器中的边界检查已关闭,但这很容易修复。为什么要添加where T:struct?这段代码中没有任何东西会妨碍类的正确性。哦,你在索引器中的边界检查是关闭的,但这很容易修复。我喜欢这个,尽管这是一个简单的方法+1,我也来看看其他答案。谢谢我接受了更详细的答案,但您的答案实际上是相同的,具有更简洁的语法优势。非常感谢你!我喜欢这样做,尽管这是一种琐碎的方式+1,我也来看看其他答案。谢谢我接受了更详细的答案,但您的答案实际上是相同的,具有更简洁的语法优势。非常感谢你!这是一个很好的答案,有示例工作代码,还有很好的语法。我一有时间就测试一下,谢谢!!是的,这种方法唯一的问题是C语言不支持多维数组的自动发现,所以你必须为每个秩组合找到一个变量…我想你可以把它推广一点,但并不完美。由于更多细节和明确提到这是一个扩展方法,我还没有使用,但肯定会看一看。这是一个很好的答案,有示例工作代码,还有很好的语法。我一有时间就测试一下,谢谢!!是的,这种方法唯一的问题是C语言不支持多维数组的自动发现,所以你必须为每个秩组合想出一个变体…我想你可以对它进行一些推广,但不是完美的。由于更多的原因而被接受 细节和明确提到,这是一个扩展方法,我还没有使用,但肯定会去看看。