1

2D 配列 ( ) の各要素に適用される関数がありますがdouble[,]、特定の次元に沿ってのみ適用されます。

目的のディメンションをパラメーターとしてメソッドに渡す方法がわからないため、2 つの関数を作成する必要がありました。最終的に、「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;
}

このような署名が必要です。2 番目のパラメーターは、インデックスを適用するディメンションです。

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

それほどきれいではありませんが、少なくともこの方法では 2 つの関数は必要ありません。

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

より一般的な方法を次に示します。いくつかのラムダを使用しているため、ラムダの使用を少し理解するのにも役立ちます。

// 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

デリゲートを渡して、関心のあるディメンションを抽出できますか? (またはラムダ)

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 の 1 次元配列を取得します。

ここでは、多次元配列の特定の部分を抽出する一般的なケースに対処しています...渡すメソッド/ラムダは、データの意味のある部分を抽出します...

于 2013-03-12T19:32:47.873 に答える