【问题标题】:Traversal of n-dimensional array via a higher-order method通过高阶方法遍历n维数组
【发布时间】:2011-11-18 06:47:36
【问题描述】:

这是一个扩展方法each,可用于将Action<int, int, T> 应用于每个元素及其对应的二维数组索引:

static public void each<T>(this T[,] a, Action<int, int, T> proc)
{
    for (int i = 0; i < a.GetLength(0); i++)
        for (int j = 0; j < a.GetLength(1); j++)
            proc(i, j, a[i, j]);
}

示例用法:

var arr = new int[3, 3];

arr.each((x, y, val) => arr[x, y] = x + y);

arr.each((x, y, val) => Console.WriteLine("{0} {1} {2}", x, y, val));

是否有可能编写一个可以处理任何等级数组的each 版本?

【问题讨论】:

  • FuncAction 采用的方法是提供大量重载。如果您在这里超出某个级别,我会争辩说这个问题太复杂了,以至于过载没有用。在某一点上,我认为该软件必须动态地适应数组中的维数才能使其易于理解。此外,您应该将您的方法命名为Each。 Initial-caps ("PascalCase") 是 .Net 中方法的命名约定。

标签: c# arrays algorithm


【解决方案1】:

无法指定具有任意数量参数的泛型,因此您必须向您的过程传递一个索引数组。最简单的方法可能是使用递归,所以这是一种递归方法。由于它使用可选参数,因此需要 C# 4.0 或更高版本。

static class Arrays
{
    public static void Each<T>(this Array a,
                               Action<int[], T> proc,
                               int[] startAt = null)
    {
        int rank = startAt == null ? 0 : startAt.Length;
        int[] indices = new int[rank + 1];
        if (rank > 0)
            startAt.CopyTo(indices, 0);
        for (int i = a.GetLowerBound(rank); i <= a.GetUpperBound(rank); i++)
        {
            indices[rank] = i;
            if (rank == a.Rank - 1)
                proc(indices, (T)a.GetValue(indices));
            else
                Each(a, proc, indices);
        }
    }
}

你可以这样称呼它:

var array = new int[1, 2, 3, 4, 5];
array.Each<int>((indices, data) => array.SetValue(indices.Sum(), indices));
array.Each<int>((indices, data) =>
      Console.WriteLine(string.Join(", ", indices) + ": " + data));

【讨论】:

  • 这个问题的出现是因为我一直在搞乱 2D 数组的 library 并且想知道是否有办法避免复制 3D 数组的所有代码。
  • 如果你只是想要这个用于 2D 和 3D 数组,手动编码可能会更容易。如果您希望它用于固定尺寸的任意大小,则生成代码可能会更好(因为此代码效率相当低)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
  • 2015-07-15
  • 2014-12-14
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多