【问题标题】:C# loop over an array of unknown dimensionsC# 循环遍历未知维度的数组
【发布时间】:2019-01-20 18:45:39
【问题描述】:

我想创建一个扩展方法来循环 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
    }
}

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

【问题讨论】:

  • @ChristianGollhardt 在 OOP 语言中使用多维数组有什么“根本错误”?您希望如何在没有多维数组的情况下进行张量操作?
  • 看来我误解了你的问题。我把尺寸误认为是尺寸的大小。 @koryakinp

标签: c# loops multidimensional-array system.array


【解决方案1】:

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

【讨论】:

  • 我认为 zcleghern 的意思类似于 ``` public static void ForEach(this Array source, Action action) { if (source.Rank == 0) { foreach (var item在源){动作((T)项目); } } else { foreach (Array arr in source) { arr.ForEach(action); } } } ```
【解决方案2】:

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

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

Link to DotNetFiddle example

【讨论】:

    【解决方案3】:

    对于那些在家玩的人来说,这有点乱,但可以让你利用yield 超过一个等级foreach

    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
    

    Full demo here

    【讨论】:

      猜你喜欢
      • 2019-08-03
      • 1970-01-01
      • 2015-04-29
      • 2013-04-01
      • 2014-12-22
      相关资源
      最近更新 更多