C# 遍历未知维度的数组
C# loop over an array of unknown dimensions
我想创建一个扩展方法来循环遍历 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
}
}
我敢肯定,有更优雅的方法可以做到这一点。但我想不通。我如何将该方法概括为无限数量的维度?
您可以尝试递归方法,在该方法中测试数组中的项目本身是否为数组。如果该项目是可迭代的,则将调用 for 循环逻辑,否则您可以对该项目进行任何您需要做的操作。如果您的对象实现了 ICollection,这应该相当简单。
如果您不关心索引,您可以在完全不知道其等级的情况下迭代 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
对于那些在家里玩的人来说,这有点混乱,但可以让你 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
我想创建一个扩展方法来循环遍历 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
}
}
我敢肯定,有更优雅的方法可以做到这一点。但我想不通。我如何将该方法概括为无限数量的维度?
您可以尝试递归方法,在该方法中测试数组中的项目本身是否为数组。如果该项目是可迭代的,则将调用 for 循环逻辑,否则您可以对该项目进行任何您需要做的操作。如果您的对象实现了 ICollection,这应该相当简单。
如果您不关心索引,您可以在完全不知道其等级的情况下迭代 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
对于那些在家里玩的人来说,这有点混乱,但可以让你 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