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

时间:2013-03-07 20:58:45

标签: 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],
   [ 42, 43, 44],
   [ 52, 53, 54]]

它没有专门使用LINQ,但我看到LINQ用于我最近遇到的每一个类似的操作。

4 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:4)

您可以尝试这样的事情:

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

sample

答案 2 :(得分:4)

@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;
    }
}

测试:

void Main()
{
    var singleArr = new int[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  
    singleArr.Slice(2, 4).Dump();
    var doubleArr = new int[,]
    {
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
    };  
    doubleArr.Slice(2, 4, 2, 4).Dump();
}

答案 3 :(得分:0)

  public class MyArraySlice<T>  where T:struct {
    public MyArraySlice(T[,] array, int xMin, int xMax, int yMin, int yMax) {
      Array = array;
      XMin = xMin; XMax = xMax;
      YMin = yMin; YMax = yMax;
    }

    public T this[int i, int j] { get {
        if (XMin <= i && i < XMax  && YMin <= j && j < YMax)
          return Array[i+XMin, j+YMin];

        throw new ArgumentOutOfRangeException();
      }
    }

    T[,] Array;
    int XMin;
    int XMax;
    int YMin;
    int YMax;
  }