3

我想创建一个扩展方法来循环System.Array未知数量的维度

现在我正在使用一种天真的方法:

public static void ForEach<T>(this Array source, Action<T> action)
{
    if(source.Rank == 1)
    {
        for (int w = 0; w < source.GetLength(0); w++)
        {
            action((T)source.GetValue(w));
        }
    }
    else if(source.Rank == 2)
    {
        for (int h = 0; h < source.GetLength(1); h++)
        {
            for (int w = 0; w < source.GetLength(0); w++)
            {
                action((T)source.GetValue(h, w));
            }
        }
    }
    else if(source.Rank == 3)
    {
        // etc
    }
}

我敢肯定,有更优雅的方式来做到这一点。但我想不通。我如何将该方法推广到无限数量的维度?

4

3 回答 3

1

如果您不关心索引,则可以在System.Array完全不知道其 Rank 的情况下迭代 a。枚举器将命中每个元素。

public class Program
{
    public static void IterateOverArray(System.Array a)
    {
        foreach (var i in a)
        {
            Console.WriteLine(i);
        }
    }

    public static void Main()
    {
        var tests = new System.Array []
        {
            new int[] {1,2,3,4,5,6,7,8},
            new int[,]
            {
                {1,2},{3,4},{5,6},{7,8}
            },
            new int[,,]
            {
                {  {1,2},{3,4} },
                {  {5,6},{7,8} }
            }
        };


        foreach (var t in tests)
        {
            Console.WriteLine("Dumping array with rank {0} to console.", t.Rank);
            IterateOverArray(t);
        }
    }
}

输出:

Dumping array with rank 1 to console.
1
2
3
4
5
6
7
8
Dumping array with rank 2 to console.
1
2
3
4
5
6
7
8
Dumping array with rank 3 to console.
1
2
3
4
5
6
7
8

链接到 DotNetFiddle 示例

于 2018-08-14T01:29:18.440 回答
1

对于那些在家玩的人来说,这有点乱,但可以让您foreach利用yield

public static IEnumerable<T> GetRank<T>(this Array source,int dimension, params int[] indexes )
{

   var indexList = indexes.ToList();
   indexList.Insert(dimension, 0);
   indexes = indexList.ToArray();

   for (var i = 0; i < source.GetLength(dimension); i++)
   {
      indexes[dimension] = i;
      yield return (T)source.GetValue(indexes);
   }
}

用法

var test1 = new int[2, 2, 3];
test1[1, 1, 0] = 1;
test1[1, 1, 1] = 2;
test1[1, 1, 2] = 3;
foreach (var item in test1.GetRank<int>(2,1,1))
{
  Console.WriteLine(item);
}

输出

1
2
3

完整的演示在这里

于 2018-08-14T01:42:28.557 回答
-1

您可以尝试递归方法,在该方法中测试数组中的项目本身是否是数组。如果项目是可迭代的,则将调用 for 循环逻辑,否则您可以对项目进行任何您需要做的操作。如果您的对象实现了 ICollection,这应该相当简单。

于 2018-08-14T01:18:21.943 回答