1

我不是 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

4 回答 4

4

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

于 2013-03-07T21:00:41.503 回答
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;
}

样本

于 2013-03-07T21:09:24.683 回答
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();
}
于 2013-03-07T21:10:21.427 回答
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;
  }
于 2013-03-07T21:10:44.680 回答