How do I 'foreach' through a two-dimensional array?
Multidimensional arrays aren't enumerable. Just iterate the good old-fashioned way:
for (int i = 0; i < table.GetLength(0); i++)
{
Console.WriteLine(table[i, 0] + " " + table[i, 1]);
}
UPDATE: I had some time on my hands, so ... I went ahead and fleshed out this idea. See below for the code.
Here's a bit of a crazy answer:
You could do what you're looking for -- essentially treat a two-dimensional array as a table with rows -- by writing a static method (perhaps an extension method) that takes a T[,]
and returns an IEnumerable<T[]>
. This would require copying each "row" of the underlying table into a new array, though.
A perhaps better (though more involved) approach would be to actually write a class that implements IList<T>
as a wrapper around a single "row" of a two-dimensional array (you would probably set IsReadOnly
to true and just implement the getter for the this[int]
property and probably Count
and GetEnumerator
; everything else could throw a NotSupportedException
). Then your static/extension method could return an IEnumerable<IList<T>>
and provide deferred execution.
That way you could write code pretty much like what you have:
foreach (IList<string> row in table.GetRows()) // or something
{
Console.WriteLine(row[0] + " " + row[1]);
}
Just a thought.
Implementation suggestion:
public static class ArrayTableHelper {
public static IEnumerable<IList<T>> GetRows<T>(this T[,] table) {
for (int i = 0; i < table.GetLength(0); ++i)
yield return new ArrayTableRow<T>(table, i);
}
private class ArrayTableRow<T> : IList<T> {
private readonly T[,] _table;
private readonly int _count;
private readonly int _rowIndex;
public ArrayTableRow(T[,] table, int rowIndex) {
if (table == null)
throw new ArgumentNullException("table");
if (rowIndex < 0 || rowIndex >= table.GetLength(0))
throw new ArgumentOutOfRangeException("rowIndex");
_table = table;
_count = _table.GetLength(1);
_rowIndex = rowIndex;
}
// I didn't implement the setter below,
// but you easily COULD (and then set IsReadOnly to false?)
public T this[int index] {
get { return _table[_rowIndex, index]; }
set { throw new NotImplementedException(); }
}
public int Count {
get { return _count; }
}
bool ICollection<T>.IsReadOnly {
get { return true; }
}
public IEnumerator<T> GetEnumerator() {
for (int i = 0; i < _count; ++i)
yield return this[i];
}
// omitted remaining IList<T> members for brevity;
// you actually could implement IndexOf, Contains, etc.
// quite easily, though
}
}
...now I think I should give StackOverflow a break for the rest of the day ;)
If you define your array like this:
string[][] table = new string[][] {
new string[] { "aa", "aaa" },
new string[]{ "bb", "bbb" }
};
Then you can use a foreach loop on it.
As others have suggested, you could use nested for-loops or redeclare your multidimensional array as a jagged one.
However, I think it's worth pointing out that multidimensional arrays are enumerable, just not in the way that you want. For example:
string[,] table = {
{ "aa", "aaa" },
{ "bb", "bbb" }
};
foreach (string s in table)
{
Console.WriteLine(s);
}
/* Output is:
aa
aaa
bb
bbb
*/