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

时间:2010-09-03 12:32:03

标签: c#

我有一个3D数组

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)
  {
  }

我试过了,但没有工作。

7 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

这应该有效:

foreach (string s in cross.SelectMany(x => x.Cast<string>()))
{
    // 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[,]维度为4x2的数组。 上方的表达式{"1", "b", "b", "b"}不代表单个数组,而是多维数组<维>中一维的值。

要实现您似乎想要的行为,Mark Cidade's answer是正确的:您无法使用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

答案 2 :(得分:1)

鉴于您的锯齿状的2D数组,您将执行经典迭代,如下所示

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 :(得分:1)

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)
   { 
   }

答案 4 :(得分:1)

3D阵列应该以我的方式看起来像这样:

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];
        }
    }
}

答案 5 :(得分:0)

foreach(String[,] abc in cross)
  foreach(string s in abc) //removed [] from inner loop
  {
      // do something with s
  }
}

答案 6 :(得分:0)

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

Iteration 1a: {"1", "b", "b", "b"}
Iteration 1b: {"b", "c", "c", "c"}
Iteration 2a: {"2", "b", "b", "e"}
Iteration 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<string> 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<T> and System.Collections.IList,
// but that would be too much unimportant code to put here
class IndexedInner<T> : IEnumerable<T>{
    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<T> GetEnumerator(){
        for(int x = 0; x < square.GetUpperBound(1); x++)
            yield return square[y, x];
    }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator(){
        return GetEnumerator();
    }
}