如何在C#中迭代3D String数组

我有一个3Darrays

String[][,] cross = {new String[,]{{"1", "b", "b", "b"}, {"b", "c", "c", "c"}},new String[,]{{"2", "b", "b", "e"}, {"b", "c", "c", "d"}}} 

如何迭代这个数组。

我想像这样迭代

 foreach(String[,] abc in cross) //abc must be the first/second 2D array foreach(string[] arr in abc) //arr must hold {"1", "b", "b", "b"} (say) { } 

我试过这个,但没有用。

给定您的锯齿状2Darrays数组 ,您将执行如下的经典迭代

 foreach (string[,] array in cross) { for (int i = 0; i < array.GetLength(0); i++) { for (int j = 0; j < array.GetLength(1); j++) { string item = array[i, j]; // do something with item } } } 

你需要3级嵌套for循环,每个维度一个

这应该工作:

 foreach (string s in cross.SelectMany(x => x.Cast())) { // Code goes here. } 

更新 :根据您的评论,看起来您希望您的枚举在某些时候处理string[] ,如下所示:

 {"1", "b", "b", "b"} 

问题是: 您声明的数组中不存在此类数组 。 这可能令人困惑,因为用于声明T[]数组的语法和用于声明T[,]数组的语法之间存在重叠。

让我们写出你的初始化,使其更清晰:

 string[][,] cross = { new string[,] { {"1", "b", "b", "b"}, {"b", "c", "c", "c"} }, new string[,] { {"2", "b", "b", "e"}, {"b", "c", "c", "d"} } }; 

我们这里有两个string[,]维数为4×2的数组。 上面的表达式{"1", "b", "b", "b"} 不表示单个数组 ,而是表示 多维数组的一维中的值

为了达到你想要的行为, Mark Cidade的回答是正确的:你不能用string[][,]来做,但你可以用string[][][]来做。

 string[][][] cross = new[] { new[] { new[] {"1", "b", "b", "b"}, new[] {"b", "c", "c", "c"} }, new[] { new[] {"2", "b", "b", "e"}, new[] {"b", "c", "c", "d"} } }; 

以上述方式声明cross允许您执行以下操作:

 foreach (string[][] abc in cross) { foreach (string[] arr in abc) { Console.WriteLine(string.Join(", ", arr)); } } 

或者,借用我原来的建议:

 foreach (string[] arr in cross.SelectMany(x => x)) { Console.WriteLine(string.Join(", ", arr)); } 

输出:

 1,b,b,b
 b,c,c,c
 2,b,b,e
 b,c,c,d

string[,]string[][]工作方式不同,它是一个方形数组,而不是数组数组。 当您在foreach语句中使用它时,枚举器将为您提供一系列单独的字符串,类似于以下内容:

 foreach(string[,] abc in cross) for(int i=0; i < abc.GetLength(0); ++i) for(int j=0; j < abc.GetLength(1); ++j) { string str = abc[i,j]; } 

如果你想要类似于迭代代码的东西,那么你需要一个string[][][]而不是string[][,]

 string[][][] cross = { new string[][]{new string[]{"1", "b", "b", "b"}, new string[]{"b", "c", "c", "c"}} ,new string[][]{new string[]{"2", "b", "b", "e"}, new string[]{"b", "c", "c", "d"}}}; foreach(string[][] abc in cross) foreach(string[] arr in abc) { } 

3Darrays应该以我的方式看起来像这样:

 string[, ,] arr = new string[,,]{ { {"a1", "b1", "c1"}, {"a2", "b2", "c2"}, {"a3", "b3", "c3"}, },{ {"a4", "b4", "c4"}, {"a5", "b5", "c5"}, {"a6", "b6", "c6"}, } }; 

并以这种方式逐个迭代所有项目:

 for (int i = 0; i < arr.GetLength(0); i++) { for (int j = 0; j < arr.GetLength(1); j++) { for (int k = 0; k < arr.GetLength(2); k++) { string s = arr[i, j, k]; } } } 
 foreach(String[,] abc in cross) foreach(string s in abc) //removed [] from inner loop { // do something with s } } 

听起来你想要的最终结果是包含2D数组的第二个元素的数组,按第一个元素分组。 所以给出你的例子,你想要这样的结果:

迭代1a:{“1”,“b”,“b”,“b”}
迭代1b:{“b”,“c”,“c”,“c”}
迭代2a:{“2”,“b”,“b”,“e”}
迭代2b:{“b”,“c”,“c”,“d”}

理解这不能有效地实现,因为2D数组不是存储为多个数组,而是存储为单个内存块。 在内存中,您的数组将看起来像这样:

 “1”,“b”,“b”,“b”,“b”,“c”,“c”,“c”,“2”,“b”,“b”,“e”,“b “,”c“,”c“,”d“

当你使用a[y, x]访问它时,正确的元素由y * a.GetLength(0) + x

如果你真的想要一个数组数组,那么你应该使用[][]而不是[,] ,这是其他人建议的。 另一方面,如果出于其他原因而难以使用多维数组,则必须构建或伪造内部数组。

要构建内部数组:

 foreach(string[,] square in cross) for(int y = 0; y < square.GetUpperBound(0); y++){ string[] inner = new string[square.GetLength(1)]; for(int x = 0; x < inner.Length; x++) inner[x] = square[y, x]; // now do something with inner } 

但这样效率很低,所以你最好假装它。 如果您以后只需要迭代它,那么您可以创建一个可枚举的:

 foreach(string[,] square in cross) for(int y = 0; y < square.GetUpperBound(0); y++){ var inner = GetEnumeratedInner(square, y); // now do something with inner } ... static IEnumerable GetEnumeratedInner(string[,] square, int y){ for(int x = 0; x < square.GetUpperBound(1); x++) yield return square[y, x]; } 

如果你真的需要通过索引访问它,就像使用数组一样,那么索引类就可以实现这一目的:

 foreach(string[,] square in cross) for(int y = 0; y < square.GetUpperBound(0); y++){ var inner = new IndexedInner(square, y); // now do something with inner } ... // this class should really implement ICollection and System.Collections.IList, // but that would be too much unimportant code to put here class IndexedInner : IEnumerable{ T[,] square; int y; public IndexedInner(T[,] square, int y){ this.square = square; this.y = y; } public int Length{get{return square.GetLength(1);}} public T this[int x]{ get{return square[y, x];} set{square[y, x] = value;} } public IEnumerator GetEnumerator(){ for(int x = 0; x < square.GetUpperBound(1); x++) yield return square[y, x]; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator(){ return GetEnumerator(); } }