Iterate Multi-Dimensional Array with Nested Foreach Statement
I think this might be a pretty simple question, but I haven't been able to figure it out yet. If I've got a 2-dimensional array like so:
int[,] ar开发者_C百科ray = new int[2,3] { {1, 2, 3}, {4, 5, 6} };
What's the best way to iterate through each dimension of the array with a nested foreach statement?
If you want to iterate over every item in the array as if it were a flattened array, you can just do:
foreach (int i in array) {
Console.Write(i);
}
which would print
123456
If you want to be able to know the x and y indexes as well, you'll need to do:
for (int x = 0; x < array.GetLength(0); x += 1) {
for (int y = 0; y < array.GetLength(1); y += 1) {
Console.Write(array[x, y]);
}
}
Alternatively you could use a jagged array instead (an array of arrays):
int[][] array = new int[2][] { new int[3] {1, 2, 3}, new int[3] {4, 5, 6} };
foreach (int[] subArray in array) {
foreach (int i in subArray) {
Console.Write(i);
}
}
or
int[][] array = new int[2][] { new int[3] {1, 2, 3}, new int[3] {4, 5, 6} };
for (int j = 0; j < array.Length; j += 1) {
for (int k = 0; k < array[j].Length; k += 1) {
Console.Write(array[j][k]);
}
}
Here's how to visit each element in a 2-dimensional array. Is this what you were looking for?
for (int i=0;i<array.GetLength(0);i++)
{
for (int j=0;j<array.GetLength(1);j++)
{
int cell = array[i,j];
}
}
With multidimensional arrays, you can use the same method to iterate through the elements, for example:
int[,] numbers2D = new int[3, 2] { { 9, 99 }, { 3, 33 }, { 5, 55 } }; foreach (int i in numbers2D) { System.Console.Write("{0} ", i); }
The output of this example is:
9 99 3 33 5 55
References
- MSDN: Using foreach with Arrays
In Java, multidimensional arrays are array of arrays, so the following works:
int[][] table = {
{ 1, 2, 3 },
{ 4, 5, 6 },
};
for (int[] row : table) {
for (int el : row) {
System.out.println(el);
}
}
I know this is an old post, but I found it through Google, and after playing with it think I have an easier solution. If I'm wrong please point it out, 'cuz I'd like to know, but this worked for my purposes at least (It's based off of ICR's response):
for (int x = 0; x < array.GetLength(0); x++)
{
Console.Write(array[x, 0], array[x,1], array[x,2]);
}
Since the both dimensions are limited, either one can be simple numbers, and thus avoid a nested for loop. I admit I'm new to C#, so please, if there's a reason not to do it, please tell me...
Use LINQ .Cast<int>()
to convert 2D array to IEnumerable<int>
.
LINQPad example:
var arr = new int[,] {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
IEnumerable<int> values = arr.Cast<int>();
Console.WriteLine(values);
Output:
The 2D array in C# does not lend itself well to a nested foreach, it is not the equivalent of a jagged array (an array of arrays). You could do something like this to use a foreach
foreach (int i in Enumerable.Range(0, array.GetLength(0)))
foreach (int j in Enumerable.Range(0, array.GetLength(1)))
Console.WriteLine(array[i, j]);
But you would still use i and j as index values for the array. Readability would be better preserved if you just went for the garden variety for
loop instead.
Two ways:
- Define the array as a jagged array, and use nested foreachs.
- Define the array normally, and use foreach on the entire thing.
Example of #2:
int[,] arr = { { 1, 2 }, { 3, 4 } }; foreach(int a in arr) Console.Write(a);
Output will be 1234. ie. exactly the same as doing i from 0 to n, and j from 0 to n.
You can use an extension method like this:
internal static class ArrayExt
{
public static IEnumerable<int> Indices(this Array array, int dimension)
{
for (var i = array.GetLowerBound(dimension); i <= array.GetUpperBound(dimension); i++)
{
yield return i;
}
}
}
And then:
int[,] array = { { 1, 2, 3 }, { 4, 5, 6 } };
foreach (var i in array.Indices(0))
{
foreach (var j in array.Indices(1))
{
Console.Write(array[i, j]);
}
Console.WriteLine();
}
It will be a bit slower than using for loops but probably not an issue in most cases. Not sure if it makes things more readable.
Note that c# arrays can be other than zero-based so you can use a for loop like this:
int[,] array = { { 1, 2, 3 }, { 4, 5, 6 } };
for (var i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++)
{
for (var j= array.GetLowerBound(1); j <= array.GetUpperBound(1); j++)
{
Console.Write(array[i, j]);
}
Console.WriteLine();
}
As mentioned elsewhere, you can just iterate over the array and it will produce all results in order across all dimensions. However, if you want to know the indices as well, then how about using this - https://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/
then doing something like:
var dimensionLengthRanges = Enumerable.Range(0, myArray.Rank).Select(x => Enumerable.Range(0, myArray.GetLength(x)));
var indicesCombinations = dimensionLengthRanges.CartesianProduct();
foreach (var indices in indicesCombinations)
{
Console.WriteLine("[{0}] = {1}", string.Join(",", indices), myArray.GetValue(indices.ToArray()));
}
You can also use enumerators. Every array-type of any dimension supports the Array.GetEnumerator method. The only caveat is that you will have to deal with boxing/unboxing. However, the code you need to write will be quite trivial.
Here's the sample code:
class Program
{
static void Main(string[] args)
{
int[,] myArray = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } };
var e = myArray.GetEnumerator();
e.Reset();
while (e.MoveNext())
{
// this will output each number from 1 to 6.
Console.WriteLine(e.Current.ToString());
}
Console.ReadLine();
}
}
int[,] arr = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for(int i = 0; i < arr.GetLength(0); i++){
for (int j = 0; j < arr.GetLength(1); j++)
Console.Write( "{0}\t",arr[i, j]);
Console.WriteLine();
}
output: 1 2 3
4 5 6
7 8 9
I was looking for a solution to enumerate an array of an unknown at compile time rank with an access to every element indices set. I saw solutions with yield but here is another implementation with no yield. It is in old school minimalistic way. In this example AppendArrayDebug() just prints all the elements into StringBuilder buffer.
public static void AppendArrayDebug ( StringBuilder sb, Array array )
{
if( array == null || array.Length == 0 )
{
sb.Append( "<nothing>" );
return;
}
int i;
var rank = array.Rank;
var lastIndex = rank - 1;
// Initialize indices and their boundaries
var indices = new int[rank];
var lower = new int[rank];
var upper = new int[rank];
for( i = 0; i < rank; ++i )
{
indices[i] = lower[i] = array.GetLowerBound( i );
upper[i] = array.GetUpperBound( i );
}
while( true )
{
BeginMainLoop:
// Begin work with an element
var element = array.GetValue( indices );
sb.AppendLine();
sb.Append( '[' );
for( i = 0; i < rank; ++i )
{
sb.Append( indices[i] );
sb.Append( ' ' );
}
sb.Length -= 1;
sb.Append( "] = " );
sb.Append( element );
// End work with the element
// Increment index set
// All indices except the first one are enumerated several times
for( i = lastIndex; i > 0; )
{
if( ++indices[i] <= upper[i] )
goto BeginMainLoop;
indices[i] = lower[i];
--i;
}
// Special case for the first index, it must be enumerated only once
if( ++indices[0] > upper[0] )
break;
}
}
For example the following array will produce the following output:
var array = new [,,]
{
{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10, 11, 12 } },
{ { 13, 14, 15 }, { 16, 17, 18 }, { 19, 20, 21 }, { 22, 23, 24 } }
};
/*
Output:
[0 0 0] = 1
[0 0 1] = 2
[0 0 2] = 3
[0 1 0] = 4
[0 1 1] = 5
[0 1 2] = 6
[0 2 0] = 7
[0 2 1] = 8
[0 2 2] = 9
[0 3 0] = 10
[0 3 1] = 11
[0 3 2] = 12
[1 0 0] = 13
[1 0 1] = 14
[1 0 2] = 15
[1 1 0] = 16
[1 1 1] = 17
[1 1 2] = 18
[1 2 0] = 19
[1 2 1] = 20
[1 2 2] = 21
[1 3 0] = 22
[1 3 1] = 23
[1 3 2] = 24
*/
精彩评论