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
*/