3

I am currently working with lots of arrays and for debugging purposes I wrote a generic Print() method to print different kinds of arrays

static void Main()
{
    Print(new double[]{ 1, 2, 3 });

    // Output: [ 1, 2, 3 ]
}

static void Print<T>(T[] array)
{
    int size = array.Length;
    if (size == 0)
        return;

    string str = "[ ";

    for (int i = 0; i < size; i++)
    {
        str += array[i].ToString();

        if (i < size - 1)
            str += ", ";
    }

    str += " ]";

    Console.WriteLine(str);
}

which works fine so far. Then I wanted to print an array of arrays, like double[][], and tried the following:

static void Main()
{
    Print(new double[][]
    {
        new double[] { 1, 2 },
        new double[] { 3, 4 },
        new double[] { 5, 6 },
    });

    // Output: [ 1, 2 ]
    //         [ 3, 4 ]
    //         [ 5, 6 ]
}

static void Print<T>(T[] array)
{
    if (array.Length == 0)
        return;

    if (array[0].GetType().IsArray)
    {
        foreach (var element in array)
        {
            Print<T>(element);
        }
    }
    else
    {
        int size = array.Length;
        string str = "[ ";

        for (int i = 0; i < size; i++)
        {
            str += array[i].ToString();

            if (i < size - 1)
                str += ", ";
        }

        str += " ]";

        Console.WriteLine(str);
    }
}

I just wanted to check if the elements of array again are arrays, and if so, I call the function Print again for each element of array. But Print(element) doesn't work, since element is of type T and not T[] and I don't know how to tell the compiler that in this case T is an array. What do I have to do to make this work?

Alexander Moser
  • 447
  • 1
  • 4
  • 16
  • One possibly important point - what youve called an array of arrays array is actually known as a jagged array. C# supports both (`double[][]` and `double[,]`). Do you need to support both or are you really only dealing with array of arrays (a jagged array). See here for more info: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/jagged-arrays – Jamiec Jul 31 '17 at 12:29
  • I need jagged arrays, since I'm playing arround with Accord.Net and their SVM's. And their methods mostly take jagged arrays as parameter. – Alexander Moser Jul 31 '17 at 12:36

2 Answers2

1

You should provide 2 overloads of your Print method - you are free to call the 1D version from the 2D version as you want:

static void Print<T>(T[][] array)
{
     Console.WriteLine("Print 2D Array");
}
static void Print<T>(T[] array)
{
     Console.WriteLine("Print 1D Array");
}

Live example: http://rextester.com/LYBUN44476

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • While this certainly fixes the problem, it is not as elegant as a single method that does this recursively. Is there no better way? – Neil Jul 31 '17 at 12:20
  • @Neil - thats a matter of opinion, IMO this is *more* elegant as the 2D version just loops through calling the 1D version. Simple, explicit, typesafe. Job done! – Jamiec Jul 31 '17 at 12:21
  • Yeah, but that way I would have to write an additional overload everytime I add a dimension to my array. Is there no way to iterate through any number of dimensions in an array? Thats the reason I tried to build this method with a recursive call to itself. – Alexander Moser Jul 31 '17 at 12:23
  • @AlexanderMoser I still think your best bet is a simple overload for each extra dimension (how many are you realistically going to have?!) Each one just calls to its predecessor - see updated live example. – Jamiec Jul 31 '17 at 12:24
  • It's a moot point, because in reality you're never likely ever going to need more than one overload for a 2 dimensional array, I agree. Though I'd have thought there'd be a way of accomplishing this in C# elegantly using one method. – Neil Jul 31 '17 at 12:26
  • Thats part of the reason I posted this question, since I couldn't find a "nicer" solution as well. I would like to know if there is a way to make it work the way I tried it. But thanks for your help :) – Alexander Moser Jul 31 '17 at 12:31
1

You can do it using dynamics:

    void Main()
    {
        Print(new double[][]
        {
            new double[] { 1, 2 },
            new double[] { 3, 4 },
            new double[] { 5, 6 },
        });

        // Output: [ 1, 2 ]
        //         [ 3, 4 ]
        //         [ 5, 6 ]
    }

    static void Print(dynamic array)
    {
        if (array.Length == 0)
            return;

        if (array[0].GetType().IsArray)
        {
            foreach (var element in array)
            {
                Print(element);
            }
        }
        else
        {
            int size = array.Length;
            string str = "[ ";

            for (int i = 0; i < size; i++)
            {
                str += array[i].ToString();

                if (i < size - 1)
                    str += ", ";
            }

            str += " ]";

            Console.WriteLine(str);
        }
    }

If you only want to test smaller part of codes - I suggest using LinqPad where you have AnyType.Dump() method and you mustn't implement anything ;)

Piotr
  • 1,155
  • 12
  • 29
  • Cool, I didn't know about dynamics. Are there any major drawbacks, since any operations regarding dynamics will be resolved at runtime? I can imagine that this could easily be a source of bugs and crashes if used too often? – Alexander Moser Jul 31 '17 at 12:50
  • There is very good SOF question about that :) https://stackoverflow.com/questions/7478387/how-does-having-a-dynamic-variable-affect-performance – Piotr Jul 31 '17 at 12:56
  • Not much use for the generic parameter now - but good answer! – Jamiec Jul 31 '17 at 13:40
  • Jamiec - you are right. There is no need for generic now. I will update answer and remove generic – Piotr Jul 31 '17 at 15:10