Traverse through n - dimensional Jagged Array

1.4k Views Asked by At

I am trying to be able to run through a jagged array but the array depth is not constant. I am looking for a clean way to go through each object in the array. right now I have a simple switch case that can handle the different levels by getting its Rank as an int for the case.

but sometimes the array is 2 levels deep and sometimes it 5 levels deep. I would like to not have to write a case for each depth level.

for example, I have a object named myObj, some times it is myObj[] or myObj[][] or myObj[][][][];

using either foreach or IEnumerator only traverses the first dimension of the array

4

There are 4 best solutions below

1
On

Your answer is recursion. I don't think this works. It would work if you had a class with child collections.

int main()
{
    CheckObj(myObject, 0);
}

void CheckObj(object myObject, int level)
{
    if(!(myObject is myObj[]))
    {
        foreach(myObj[] o in (myObj[][])myObject)
        {
            CheckObj(o, level + 1);
        }
    }
    else
    {
        //do what you need to do with myObj[]
    }
}
0
On

Something like this?

    static void Main(string[] args)
    {
        int[][][] x = new int[][][]
        {
            new int[][]
            {
                new int [] { 1, 2, 3, 4 },
                new int [] { 5, 6 },
                new int [] { 7 }
            },
            new int[][]
            {
                new int [] { 8 },
                new int [] { 9, 10 },
                new int [] { 11, 12, 13, 14 }
            }
        };

        DeepEnumerateArray(x);
        Console.ReadLine();
    }

    static void DeepEnumerateArray(Array x)
    {
        if (x.Length == 0)
            return;

        object first = x.GetValue(0);
        if (first is Array)
        {
            foreach (Array y in x)
                DeepEnumerateArray(y);
        }
        else
        {
            foreach (object z in x)
                Console.WriteLine(z);
        }
    }
0
On

This should do it. . .

private static void EnumerateObjects(Array items)
{
    foreach (var item in items)
    {
        if (item is Array)
        {
            EnumerateObjects((Array)item);
        }
        else if (item is MyObject)
        {
            Console.WriteLine(item);
        }
    }
}
1
On

Here's an extension method to traverse jagged/multidimensional arrays (similar to David B. one's but with yield, null handling and type casting):

public static class Extensions
{
    public static IEnumerable<T> Traverse<T>(this Array array)
    {
        foreach (object val in array)
        {
            if (val == null)
                continue; //null means empty sub-array --> skip it
            if (val is Array)
            {
                var subArray = (Array)val;
                foreach (var value in subArray.Traverse<T>())
                    yield return value;
            }
            else
            {
                yield return (T)val;
            }
        }
    }
}

Usage example:

class Program
{
    static void Main(string[] args)
    {
        int[][][] jagged = new int[4][][];

        jagged[0] = new int[2][] { new[] { 0, 1 }, new[] { 2, 3, 4 } };
        jagged[1] = new int[3][] { new[] { 5, 6, 7 }, new[] { 8, 9, 10 }, new[] { 11, 12 } };
        jagged[3] = new int[4][] { new[] { 13, 14 }, null, new[] { 15, }, new[] { 16 } };

        var jaggedElements = jagged.Traverse<int>().ToList();
        // contains:  1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16

       int[, ,] multi = new[, ,] { { { 1, 2 }, { 3, 4 } },
                        { { 4, 5 }, { 6, 7 } }, 
                        { { 8, 9 }, { 10, 11 } } };


       var multiElements = multi.Traverse<int>().ToList();
       // contains:  1,2,3,4,5,6,7,8,9,10,11

    }
}