1

我有一个函数应用于二维数组 ( double[,]) 的每个元素,但仅沿给定维度。

我不得不创建两个函数,因为我不知道如何将所需的维度作为参数传递给方法。我最终得到了一个“vertical_foo”和一个“horizo​​ntal_foo”函数,它们几乎相同:

private double[,] vertical_foo (double[,] a) {

    int height = a.GetLength(0);
    int width = a.GetLength(1);          

    var result = new double[height, weight];

    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {

            // Here I use first ("i") dimension
            int before =  Math.Max(i-1, 0);
            int after = Math.Min(i+1, height-1);
            result[i,j] = (a[after, j] - a[before, j]) * 0.5;
        }
    }
    return result;
}

private double[,] horizontal_foo (double[,] a) {

    int height = a.GetLength(0);
    int width = a.GetLength(1);          

    var result = new double[height, weight];

    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {

            // Here I use second ("j") dimension
            int before =  Math.Max(j-1, 0);
            int after = Math.Min(j+1, height-1);
            result[i,j] = (a[i, after] - a[i, before]) * 0.5;
        }
    }
    return result;
}

我想要这样的签名,其中第二个参数是我要应用索引的维度:

private double[,] general_foo (double[,] a, int dimension) {}

非常欢迎任何建议!

4

3 回答 3

1

沿着这些路线做某事是否可以接受?

int before_i = i, after_i = i;
int before_j = j, after_j = j;
switch( dimension ) {
   case 0:
      before_i = Math.max(i-1,0);
      after_i = Math.min(i+1, width-1);
      break;
   case 1:
      before_j = Math.max(j-1,0);
      after_j = Math.min(j+1, height-1);
      break;
}
result[ i, j ] = (a[after_i, after_j] - a[before_i,before_j]) * 0.5

它不是非常漂亮,但至少这样你不需要两个函数。

于 2013-03-12T19:24:20.803 回答
1

我将对此进行尝试:

private double[,] general_foo(double[,] a, int dimension)
{
    var w = a.GetLength(0);
    var h = a.GetLength(1);
    var result = new double[w, h];
    var otherDimension = 1 - dimension; // NOTE only works for 2D arrays
    var otherDimensionLength = a.GetLength(otherDimension);
    var dimensionLength = a.GetLength(dimension);
    for (int i = 0; i < dimensionLength; i++)
    {
        for (int j = 0; j < otherDimensionLength; j++)
        {
            var setIndexes = new int[2] { j, j };
            setIndexes[dimension] = i;

            var beforeIndexes = new int[2] { j, j };
            beforeIndexes[dimension] = Math.Max(i - 1, 0);

            var afterIndexes = new int[2] { j, j };
            afterIndexes[dimension] = Math.Min(i + 1, dimensionLength - 1);

            var beforeValue = (double)a.GetValue(beforeIndexes);
            var afterValue = (double)a.GetValue(afterIndexes);
            result.SetValue((afterValue - beforeValue) * 0.5, setIndexes);
        }
    }

    return result;
} 

这是一个更通用的方法。它使用了一些 lambda,因此它也可以帮助您了解 lambda 的使用。

// Iterates through every item in a multidementional array array
private Array MutateArray<T>(Array a, Func<T, int[], T> selector)
{
    var rank = a.Rank;
    var lengths = Enumerable.Range(0, a.Rank)
                            .Select(r => a.GetLength(r))
                            .ToArray(); // Get length of a in each dimension
    var result = Array.CreateInstance(typeof(T), lengths);
    var index = new int[a.Rank];
    foreach (T item in a) // flattens array
    {
        result.SetValue(selector(item, index), index);

        // Get next index value (I'm sure this could be improved)
        for (var d = 0; d < rank; d++)
        {
            if (index[d] == lengths[d] - 1)
            {
                index[d] = 0;
            }
            else
            {
                index[d]++;
                break;
            }
        }
    }

    return result;
}

// Your "foo" method
private double[,] generic_foo(double[,] a, int d)
{
    var upperD = a.GetUpperBound(d);
    return (double[,])MutateArray<double>(a, (x, i) =>
    {
        var prev = i.ToArray(); // clone
        prev[d] = Math.Max(prev[d] - 1, 0);

        var next = i.ToArray(); // clone
        next[d] = Math.Min(next[d] + 1, upperD);

        var prevVal = (double)a.GetValue(prev);
        var nextVal = (double)a.GetValue(next);
        return (nextVal - prevVal) * 0.5;
    });
}
于 2013-03-12T19:31:07.403 回答
0

你可以传入一个委托来提取你感兴趣的维度吗?(或 lambda)

Func<int[,],int,int[]> accessor这里表示函数的签名(其中最后一个模板参数是返回类型)

   private void Working()
   {
       DoSomething(GetRow,1);

   }

因此,在本例中,您希望“DoSomething”工作者连续工作。

    private void DoSomething(Func<int[,],int,int[]> accessor, int Idx)
   { 
       int[,] theData = {{1,1,1,1,1},{2,2,2,2,2}};           
       int[] someData = accessor(theData,Idx);
   }


   public int[] GetRow(int[,] data,int index)
   {
       List<int> numbers = new List<int>();

       for (int i = 0; i < data.GetLength(1); i++)
       {
           numbers.Add(data[index, i]);
       }
       return numbers.ToArray();
   }

在上面的例子中,你得到一个 2,2,2,2,2 的一维数组

我在这里解决提取多维数组的特定部分的一般情况...您传入的方法/ lambda 提取数据的有意义的部分...

于 2013-03-12T19:32:47.873 回答