Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Simple Programming Challenge: N-dimensional array iteration

I've always been a fan of solutions that cover as many cases as possible. A long while back I remember iterating through an array and being annoyed when I had to rewrite or alter loop logic, or write a few variants of the code, because the structure of the data was changing in a way that made the number of dimensions variable. While checking the type and giving a bit of code for case a, b or c of dimensions (rank) 1, 4, or 3, the code became annoying to write, so I wondered: how can I write this in a way that's non-recursive and covers each possible option?

The following solution came to mind when I discovered a new feature I hadn't really used, iterators. The code's a bit old, but it still works, I haven't been able to find a good example of the same online anywhere. Which is surprising, if anyone else knows of one, please point it out, for reference's sake.

Code:
[font=courier new][color=#008000]/// <summary>[/color]

[color=#008000]/// Obtains an enumerable object which can iterate through all of[/color]

[color=#008000]/// the indices of an <see cref="Array"/> regardless of its [/color]

[color=#008000]/// dimensional complexity.[/color]

[color=#008000]/// </summary>[/color]

[color=#008000]/// <param name="array">The <see cref="Array"/> to perform[/color]

[color=#008000]/// iteration on.</param>[/color]

[color=#008000]/// <returns>A <see cref="IEnumerable{T}"/> object that[/color]

[color=#008000]/// yields a single-dimensional array per iteration relative[/color]

[color=#008000]/// to the <paramref name="array"/> provided.</returns>[/color]

[color=#008000]/// <remarks><para>The number of values in the resultant array,[/color]

[color=#008000]/// per iteration, is equivalent to the[/color]

[color=#008000]/// <see cref="Array.ArrayRank"/> of the [/color]

[color=#008000]/// <paramref name="array"/> provided.</para>[/color]

[color=#008000]/// <para>Due to the nature this method was intended to be used,[/color]

[color=#008000]/// the array retrieved per iteration is the same so it is not[/color]

[color=#008000]/// guaranteed to be the same on a much later access[/color]

[color=#008000]/// should its reference be stored, and the iteration[/color]

[color=#008000]/// continued.</para></remarks>[/color]

[color=#0000FF]public[/color] [color=#0000FF]static[/color] [color=#008080]IEnumerable[/color][color=#808000]<[/color][color=#0000FF]int[/color][color=#808080][[/color][color=#808080]][/color][color=#808000]>[/color] [color=#008080]Iterate[/color][color=#808080]([/color][color=#0000FF]this[/color] [color=#008080]Array[/color] [color=#008080]array[/color][color=#808080])[/color]

[color=#808080]{[/color]

    [color=#0000FF]int[/color][color=#808080][[/color][color=#808080]][/color] [color=#008080]indices[/color][color=#808080];[/color]

    [color=#0000FF]int[/color] [color=#008080]rank[/color] [color=#808000]=[/color] [color=#008080]array[/color][color=#808080].[/color][color=#008080]Rank[/color][color=#808080];[/color]

    [color=#0000FF]if[/color] [color=#808080]([/color][color=#008080]rank[/color] [color=#808000]==[/color] [color=#FF0000]1[/color] [color=#808000]&&[/color] [color=#008080]array[/color][color=#808080].[/color][color=#008080]GetLowerBound[/color][color=#808080]([/color][color=#FF0000]0[/color][color=#808080])[/color] [color=#808000]==[/color] [color=#FF0000]0[/color][color=#808080])[/color]

    [color=#808080]{[/color]

        [color=#008000]/* *[/color]

        [color=#008000] * Simple answer for one dimension[/color]

        [color=#008000] * */[/color]

        [color=#008080]indices[/color] [color=#808000]=[/color] [color=#0000FF]new[/color] [color=#0000FF]int[/color][color=#808080][[/color][color=#808080]][/color] [color=#808080]{[/color] [color=#008080]array[/color][color=#808080].[/color][color=#008080]GetLowerBound[/color][color=#808080]([/color][color=#FF0000]0[/color][color=#808080])[/color] [color=#808080]}[/color][color=#808080];[/color]

        [color=#0000FF]int[/color] [color=#008080]upperBound[/color] [color=#808000]=[/color] [color=#008080]array[/color][color=#808080].[/color][color=#008080]GetUpperBound[/color][color=#808080]([/color][color=#FF0000]0[/color][color=#808080])[/color][color=#808080];[/color]

        [color=#0000FF]for[/color] [color=#808080]([/color][color=#808080];[/color] [color=#008080]indices[/color][color=#808080][[/color][color=#FF0000]0[/color][color=#808080]][/color] [color=#808000]<=[/color] [color=#008080]upperBound[/color][color=#808080];[/color] [color=#008080]indices[/color][color=#808080][[/color][color=#FF0000]0[/color][color=#808080]][/color][color=#808000]++[/color][color=#808080])[/color]

            [color=#0000FF]yield[/color] [color=#0000FF]return[/color] [color=#008080]indices[/color][color=#808080];[/color]

    [color=#808080]}[/color]

    [color=#0000FF]else[/color]

    [color=#808080]{[/color]

        [color=#008000]/* *[/color]

        [color=#008000] * Multi-dimensional, or non-vector, arrays are a bit different.[/color]

        [color=#008000] * */[/color]

        [color=#008080]indices[/color] [color=#808000]=[/color] [color=#0000FF]new[/color] [color=#0000FF]int[/color][color=#808080][[/color][color=#008080]array[/color][color=#808080].[/color][color=#008080]Rank[/color][color=#808080]][/color][color=#808080];[/color]

        [color=#008000]/* *[/color]

        [color=#008000] * Obtain the upper/lower bounds..[/color]

        [color=#008000] * */[/color]

        [color=#0000FF]int[/color][color=#808080][[/color][color=#808080]][/color] [color=#008080]upperBounds[/color] [color=#808000]=[/color] [color=#0000FF]new[/color] [color=#0000FF]int[/color][color=#808080][[/color][color=#008080]array[/color][color=#808080].[/color][color=#008080]Rank[/color][color=#808080]][/color][color=#808080];[/color]

 

        [color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i[/color] [color=#808000]=[/color] [color=#FF0000]0[/color][color=#808080];[/color] [color=#008080]i[/color] [color=#808000]<[/color] [color=#008080]rank[/color][color=#808080];[/color] [color=#008080]i[/color][color=#808000]++[/color][color=#808080])[/color]

        [color=#808080]{[/color]

            [color=#008080]indices[/color][color=#808080][[/color][color=#008080]i[/color][color=#808080]][/color] [color=#808000]=[/color] [color=#008080]array[/color][color=#808080].[/color][color=#008080]GetLowerBound[/color][color=#808080]([/color][color=#008080]i[/color][color=#808080])[/color][color=#808080];[/color]

            [color=#008080]upperBounds[/color][color=#808080][[/color][color=#008080]i[/color][color=#808080]][/color] [color=#808000]=[/color] [color=#008080]array[/color][color=#808080].[/color][color=#008080]GetUpperBound[/color][color=#808080]([/color][color=#008080]i[/color][color=#808080])[/color][color=#808080];[/color]

        [color=#808080]}[/color]

 

        [color=#0000FF]int[/color][color=#808080][[/color][color=#808080]][/color] [color=#008080]lowerBounds[/color] [color=#808000]=[/color] [color=#808080]([/color][color=#0000FF]int[/color][color=#808080][[/color][color=#808080]][/color][color=#808080])[/color][color=#008080]indices[/color][color=#808080].[/color][color=#008080]Clone[/color][color=#808080]([/color][color=#808080])[/color][color=#808080];[/color]

 

    [color=#008080]Repeater[/color][color=#808080]:[/color]

        [color=#808080]{[/color]

            [color=#008000]/* *[/color]

            [color=#008000] * Nifty thing is... it's always the same array,[/color]

            [color=#008000] * which means there's no performance hit for[/color]

            [color=#008000] * creating and returning new arrays.[/color]

            [color=#008000] * */[/color]

            [color=#0000FF]yield[/color] [color=#0000FF]return[/color] [color=#008080]indices[/color][color=#808080];[/color]

            [color=#008000]/* *[/color]

            [color=#008000] * Move through the dimensions, starting [/color]

            [color=#008000] * with the highest-order.[/color]

            [color=#008000] * */[/color]

            [color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i[/color] [color=#808000]=[/color] [color=#008080]rank[/color] [color=#808000]-[/color] [color=#FF0000]1[/color][color=#808080];[/color] [color=#008080]i[/color] [color=#808000]>=[/color] [color=#FF0000]0[/color][color=#808080];[/color] [color=#008080]i[/color][color=#808000]--[/color][color=#808080])[/color]

            [color=#808080]{[/color]

                [color=#008000]/* *[/color]

                [color=#008000] * Index the current dimension...[/color]

                [color=#008000] * */[/color]

                [color=#008080]indices[/color][color=#808080][[/color][color=#008080]i[/color][color=#808080]][/color][color=#808000]++[/color][color=#808080];[/color]

                [color=#008000]/* *[/color]

                [color=#008000] * If the current dimension is in range[/color]

                [color=#008000] * we're done.[/color]

                [color=#008000] * */[/color]

                [color=#0000FF]if[/color] [color=#808080]([/color][color=#008080]indices[/color][color=#808080][[/color][color=#008080]i[/color][color=#808080]][/color] [color=#808000]<=[/color] [color=#008080]upperBounds[/color][color=#808080][[/color][color=#008080]i[/color][color=#808080]][/color][color=#808080])[/color]

                    [color=#0000FF]break[/color][color=#808080];[/color]

                [color=#008000]/* *[/color]

                [color=#008000] * Reset the current index, the loop[/color]

                [color=#008000] * will continue until all 'overflows' [/color]

                [color=#008000] * on the array are hit and reset [/color]

                [color=#008000] * accordingly.[/color]

                [color=#008000] * */[/color]

                [color=#008080]indices[/color][color=#808080][[/color][color=#008080]i[/color][color=#808080]][/color] [color=#808000]=[/color] [color=#008080]lowerBounds[/color][color=#808080][[/color][color=#008080]i[/color][color=#808080]][/color][color=#808080];[/color]

                [color=#008000]/* *[/color]

                [color=#008000] * If the first dimension has been incremented[/color]

                [color=#008000] * and exceeded the high point of the dimension[/color]

                [color=#008000] * exit stage left.[/color]

                [color=#008000] * */[/color]

                [color=#0000FF]if[/color] [color=#808080]([/color][color=#008080]i[/color] [color=#808000]==[/color] [color=#FF0000]0[/color][color=#808080])[/color]

                    [color=#0000FF]yield[/color] [color=#0000FF]break[/color][color=#808080];[/color]

            [color=#808080]}[/color]

            [color=#0000FF]goto[/color] [color=#008080]Repeater[/color][color=#808080];[/color]

        [color=#808080]}[/color]

    [color=#808080]}[/color]

    [color=#0000FF]yield[/color] [color=#0000FF]break[/color][color=#808080];[/color]

[color=#808080]}[/color][/font]

The code for this aims to enable you to loop through an array arbitrarily, giving you the index of each element. This is very useful if you're stepping through a non-standard array, like the one created thusly:
Code:
[font=courier new][color=#0000FF]int[/color][color=#808080][[/color][color=#808080],[/color] [color=#808080],[/color] [color=#808080],[/color] [color=#808080],[/color] [color=#808080],[/color] [color=#808080],[/color][color=#808080]][/color] [color=#008080]values[/color] [color=#808000]=[/color] [color=#808080]([/color][color=#0000FF]int[/color][color=#808080][[/color][color=#808080],[/color] [color=#808080],[/color] [color=#808080],[/color] [color=#808080],[/color] [color=#808080],[/color] [color=#808080],[/color][color=#808080]][/color][color=#808080])[/color][color=#008080]Array[/color][color=#808080].[/color][color=#008080]CreateInstance[/color][color=#808080]([/color][color=#0000FF]typeof[/color][color=#808080]([/color][color=#0000FF]int[/color][color=#808080])[/color][color=#808080],[/color] [color=#0000FF]new[/color] [color=#0000FF]int[/color][color=#808080][[/color][color=#808080]][/color] [color=#808080]{[/color] [color=#FF0000]4[/color][color=#808080],[/color] [color=#FF0000]4[/color][color=#808080],[/color] [color=#FF0000]4[/color][color=#808080],[/color] [color=#FF0000]4[/color][color=#808080],[/color] [color=#FF0000]4[/color][color=#808080],[/color] [color=#FF0000]4[/color][color=#808080],[/color] [color=#FF0000]4[/color] [color=#808080]}[/color][color=#808080],[/color] [color=#0000FF]new[/color] [color=#0000FF]int[/color][color=#808080][[/color][color=#808080]][/color] [color=#808080]{[/color] [color=#808000]-[/color][color=#FF0000]3[/color][color=#808080],[/color] [color=#FF0000]15[/color][color=#808080],[/color] [color=#FF0000]1024[/color][color=#808080],[/color] [color=#FF0000]58[/color][color=#808080],[/color] [color=#808000]-[/color][color=#FF0000]90[/color][color=#808080],[/color] [color=#FF0000]3[/color][color=#808080],[/color] [color=#808000]-[/color][color=#FF0000]1[/color] [color=#808080]}[/color][color=#808080])[/color][color=#808080];[/color][/font]
Each dimension is only 4 items in size, but due to the way arrays work, there's 4^7 (16,384) items within it, the starting indices for each are -3, 15, 1024, 58, -90, 3, -1. Iterating through this using traditional means involves advance knowledge of the array, which, when you're given a value of type Array, this can sometimes be difficult or cumbersome to write for every case without a variable solution.

You might ask, why go through such trouble when you can iterate through them arbitrarily without knowledge of the indices of the elements? Simple, without this knowledge, you can't alter the array, it's also easier to debug information about an array if you know where within it you are (versus building a series of nested loops that individually track each dimension, which goes back to the first problem: advance knowledge of the array.)

Here's an example, in the above array, if you wanted to square each element, you'd have to build a seven-stage series of loops, which is ugly, if you don't use a dynamic solution and you're creating a generic 'Square' function for arrays, you'd have to use a different bit of code for each rank of the array. Naturally you could use fourteen more variables to define the upper and lower bounds of the array, but the example's annoying enough as it is:
Code:
[font=courier new][color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i1[/color] [color=#808000]=[/color] [color=#808000]-[/color][color=#FF0000]3[/color][color=#808080];[/color] [color=#008080]i1[/color] [color=#808000]<=[/color] [color=#FF0000]0[/color][color=#808080];[/color] [color=#008080]i1[/color][color=#808000]++[/color][color=#808080])[/color]

    [color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i2[/color] [color=#808000]=[/color] [color=#FF0000]15[/color][color=#808080];[/color] [color=#008080]i2[/color] [color=#808000]<=[/color] [color=#FF0000]18[/color][color=#808080];[/color] [color=#008080]i2[/color][color=#808000]++[/color][color=#808080])[/color]

        [color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i3[/color] [color=#808000]=[/color] [color=#FF0000]1024[/color][color=#808080];[/color] [color=#008080]i3[/color] [color=#808000]<=[/color] [color=#FF0000]1027[/color][color=#808080];[/color] [color=#008080]i3[/color][color=#808000]++[/color][color=#808080])[/color]

            [color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i4[/color] [color=#808000]=[/color] [color=#FF0000]58[/color][color=#808080];[/color] [color=#008080]i4[/color] [color=#808000]<=[/color] [color=#FF0000]61[/color][color=#808080];[/color] [color=#008080]i4[/color][color=#808000]++[/color][color=#808080])[/color]

                [color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i5[/color] [color=#808000]=[/color] [color=#808000]-[/color][color=#FF0000]90[/color][color=#808080];[/color] [color=#008080]i5[/color] [color=#808000]<=[/color] [color=#808000]-[/color][color=#FF0000]87[/color][color=#808080];[/color] [color=#008080]i5[/color][color=#808000]++[/color][color=#808080])[/color]

                    [color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i6[/color] [color=#808000]=[/color] [color=#FF0000]3[/color][color=#808080];[/color] [color=#008080]i6[/color] [color=#808000]<=[/color] [color=#FF0000]6[/color][color=#808080];[/color] [color=#008080]i6[/color][color=#808000]++[/color][color=#808080])[/color]

                        [color=#0000FF]for[/color] [color=#808080]([/color][color=#0000FF]int[/color] [color=#008080]i7[/color] [color=#808000]=[/color] [color=#808000]-[/color][color=#FF0000]1[/color][color=#808080];[/color] [color=#008080]i7[/color] [color=#808000]<=[/color] [color=#FF0000]2[/color][color=#808080];[/color] [color=#008080]i7[/color][color=#808000]++[/color][color=#808080])[/color]

                            [color=#008080]values[/color][color=#808080][[/color][color=#008080]i1[/color][color=#808080],[/color] [color=#008080]i2[/color][color=#808080],[/color] [color=#008080]i3[/color][color=#808080],[/color] [color=#008080]i4[/color][color=#808080],[/color] [color=#008080]i5[/color][color=#808080],[/color] [color=#008080]i6[/color][color=#808080],[/color] [color=#008080]i7[/color][color=#808080]][/color] [color=#808000]*=[/color] [color=#008080]values[/color][color=#808080][[/color][color=#008080]i1[/color][color=#808080],[/color] [color=#008080]i2[/color][color=#808080],[/color] [color=#008080]i3[/color][color=#808080],[/color] [color=#008080]i4[/color][color=#808080],[/color] [color=#008080]i5[/color][color=#808080],[/color] [color=#008080]i6[/color][color=#808080],[/color] [color=#008080]i7[/color][color=#808080]][/color][color=#808080];[/color][/font]
Personally this is easier for me:
Code:
[font=courier new][color=#0000FF]foreach[/color] [color=#808080]([/color][color=#008080]var[/color] [color=#008080]indices[/color] [color=#0000FF]in[/color] [color=#008080]values[/color][color=#808080].[/color][color=#008080]Iterate[/color][color=#808080]([/color][color=#808080])[/color][color=#808080])[/color]

    [color=#008080]values[/color][color=#808080].[/color][color=#008080]SetValue[/color][color=#808080]([/color][color=#808080]([/color][color=#808080]([/color][color=#0000FF]int[/color][color=#808080])[/color][color=#008080]Math[/color][color=#808080].[/color][color=#008080]Pow[/color][color=#808080]([/color][color=#808080]([/color][color=#0000FF]int[/color][color=#808080])[/color][color=#008080]values[/color][color=#808080].[/color][color=#008080]GetValue[/color][color=#808080]([/color][color=#008080]indices[/color][color=#808080])[/color][color=#808080],[/color][color=#FF0000]2[/color][color=#808080])[/color][color=#808080])[/color][color=#808080],[/color] [color=#008080]indices[/color][color=#808080])[/color][color=#808080];[/color][/font]
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top