Saturday, 2 May 2015

Array: 2-Dimensional

Previously we created a simple one-dimensional array, basically a row or a column in a table. Today let's create our first multi-dimensional array. We are going to work our way up to not one, but two dimensions.  

Fun fact an array can have multiple dimensions or indices, in C# it can go up to 32 at the time of this post, however I have never seen it go beyond 3, nor could I fathom a situation beyond the need of 4; that said If you are a physicist, I'm sure you could make the argument that you could use 7 or 10 dimensions, or whatever is the maximum that your fragile ego can hold. Thats said if you need more than four you should most likely rethink if C# is the right language for you, you should probably be looking at C++ or F# instead.

Any way 2 dimensional arrays are initialized similarly to single dimensional ones.


    int[,] myInts = new int[3,2];

    myInts [0, 0] = 1;
    myInts [0, 1] = 2;
    myInts [1, 0] = 3;
    myInts [1, 1] = 4;
    myInts [2, 0] = 5;
    myInts [2, 1] = 6;


or


    int[,] myInts = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } };


The resulting data structure will appear something along the lines of

1 2
3 4
5 6

It's really a matter of perspective, but generally it's accepted that your first index number is your column, and your second index number is your row.


    int[,] myInts = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } };

    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 2; j++)
            Console.WriteLine($"value {myInts[i,j]} is at {i},{j}" );
           
    Console.WriteLine("\nLength: {0}", myInts.Length);
    Console.WriteLine("Rank: {0}", myInts.Rank);




The length property still returns the total number of elements in Array, however the Rank property returns the total number of dimensions. In the above example we can see that there as 6 elements in our array, however there are 2 dimensions

A caveat of arrays is that when duplicating an array using the Clone() function we create a shallow copy of our array. A shallow copy is a tricky concept to wrap one's head around at first, at a very high level, when dealing with data we have two concepts, the Stack and the Heap, you can think of the stack as an index to the heap. When we create a shallow copy of something we add a second reference to the heap and put that reference on the stack.

If you make changes to a shallow copy that change will be reflected in the original however this shallow copy is restricted to the actual elements within the array and not the array itself. meaning that if instead up updating elements we replace them with newly instantiated ones we break the reference to the original item.

That might sound a bit confusing, so let's illustrate this point, start by creating a very simple person class.

    
    public class Person
    {
        public string Name { get; set; }
        public int BirthYear { get; set; }
        public Person(string Name, int BirthYear)
        {
            this.Name = Name;
            this.BirthYear = BirthYear;
        }

        public override string ToString()
        {
            return $"{this.Name} born {this.BirthYear}";
        }
    }


Above we create a Person class with two properties, a name and a birthyear, two things that a commonly used to identify people. 


Next let's create a Person class, add two elements to it and clone it.


    Person[] orginal = new Person[] { new Person("Pawel", 84), new Person("Tomek", 88) };

    Console.WriteLine("\nPeople in the Original Array");
    foreach(var p in orginal)
        Console.WriteLine(p);

    Person[] cloned = (Person[])orginal.Clone();

    Console.WriteLine("\nPeople in the cloned Array");
    foreach(var p in orginal)
        Console.WriteLine(p);


nothing special if we run our code, we'll get the following.


exactly what one would expect, we create an array, clone it and everything comes out looking the same, but now let's change Pawel to Natalia, born in 89.


    Person[] orginal = new Person[] { new Person("Pawel", 84), new Person("Tomek", 88) };

    Console.WriteLine("\nPeople in the Original Array");
    foreach(var p in orginal)
        Console.WriteLine(p);

    Person[] cloned = (Person[])orginal.Clone();

    Console.WriteLine("\nPeople in the cloned Array");
    foreach(var p in cloned)
        Console.WriteLine(p);


    //First elmenent of cloned array changed
    cloned[0].Name = "Natalia";
    cloned[0].BirthYear = 89;

    Console.WriteLine("\nPeople in the Original Array after first element updated in cloned array");
    foreach(var p in orginal)
        Console.WriteLine(p);

    Console.WriteLine("\nPeople in the cloned Array after first element updated in cloned array");
    foreach(var p in cloned)
        Console.WriteLine(p);


now this is probably a less than desirable situation, as you can see above, we changed the properties of the first element in our cloned array, and they were updated in both the original as well as cloned arrays.  


Most likely not what we had in mind, now the strange part is that this shallow copy isn't to the actual array, it's to the elements of the array, meaning that if we instead instantiate a new first element for our cloned array, the original should not be affected.


    Person[] orginal = new Person[] { new Person("Pawel", 84), new Person("Tomek", 88) };

    Console.WriteLine("\nPeople in the Original Array");
    foreach(var p in orginal)
        Console.WriteLine(p);

    Person[] cloned = (Person[])orginal.Clone();

    Console.WriteLine("\nPeople in the cloned Array");
    foreach(var p in cloned)
        Console.WriteLine(p);

    Console.WriteLine("\nInstantiate a new first element of the cloned array");
    Console.WriteLine("with properties Natalia and 89");
    cloned[0] = new Person("Natalia", 89);

    Console.WriteLine("\nPeople in the Original Array after first element reinitalized in cloned array");
    foreach(var p in orginal)
        Console.WriteLine(p);

    Console.WriteLine("\nPeople in the cloned Array after first element reinitalized in cloned array");
    foreach(var p in cloned)
        Console.WriteLine(p);
    Console.WriteLine();


In the above rather than changing the properties of the first element, we instead reinitialized that first element in the cloned array and thus the change is not reflected in the original array.


and that's all for this one.