#136 – Sorting an Array of Values Based on an Array of Keys

You can use the Array.Sort method to sort two arrays at the same time.  The values of one array are used as the keys to determine the sort order and the values of the second array are just changed to match the sequence of the first array.

Array.Sort takes two arrays.  The first is an array of keys, dictating how the elements will be sorted.  The second will just be reordered to match the sequence of the first array.

Here’s an example:

            string[] titles = { "Pride and Prejudice", "Moby-Dick", "A Tale of Two Cities",
                                "Anna Karenina", "Fahrenheit 451" };
            string[] firstWords = {
                "It is a truth universally acknowledged",
                "Call me Ishmael",
                "It was the best of times",
                "All happy families are alike",
                "It was a pleasure to burn" };

            Array.Sort(titles, firstWords);   // Sort by title

Here’s what both arrays look like after sorting:

#135 – Implementing IComparable to Allow Sorting a Custom Type

Arrays of elements that belong to a custom type cannot be sorted, unless the type implements the IComparable interface.

To make elements of a custom type sortable, you need to implement IComparable in your type.  IComparable consists of the single method CompareTo, which compares two objects.

Here’s an example of a Person class implementing CompareTo to sort people in LastName/FirstName order:

            public int CompareTo(object obj)
            {
                Person other = obj as Person;
                if (other == null)
                    throw new ArgumentException("Object is not a Person");
                else
                {
                    // Sort by LastName, then by FirstName (ignore case)
                    int compare = this.LastName.ToLower().CompareTo(other.LastName.ToLower());
                    if (compare == 0)
                        compare = this.FirstName.ToLower().CompareTo(other.FirstName.ToLower());

                    return compare;
                }

Here’s an example of sorting an array of Person objects:

            Person[] folks = new Person[4];
            folks[0] = new Person("Bronte", "Emily");
            folks[1] = new Person("Bronte", "Charlotte");
            folks[2] = new Person("Tennyson", "Alfred");
            folks[3] = new Person("Mailer", "Norman");
            Array.Sort(folks);    // C. Bronte, E. Bronte, Mailer, Tennyson

#134 – Sorting One-Dimensional Arrays

You can sort a one-dimensional array of elements using the static Array.Sort method.  This requires that the underlying type of the array elements implements the IComparable interface.  Types that implement IComparable include: all built-in numeric types (e.g. int, float, double), char, string and DateTime types.

Here’s an example that sorts an array of integers:

 int[] nums = new int[5];
 nums[0] = 3; nums[1] = 2; nums[2] = 4;
 nums[3] = 1; nums[4] = 0;

 Array.Sort(nums);   // Elements now: 0, 1, 2, 3, 4

Here’s an example of sorting an array of strings:

 string[] emps = new string[4];
 emps[0] = "Augustus";
 emps[1] = "Tiberius";
 emps[2] = "Caligula";
 emps[3] = "Claudius";
 Array.Sort(emps);   // Augustus, Caligula, Claudius, Tiberius

You can’t sort an array of objects, if the element type does not implement IComparable:

 Cat[] cats = new Cat[2];
 cats[0] = new Cat("Garfield", "Sleep all day");
 cats[1] = new Cat("Buster", "Scratch everything");
 Array.Sort(cats);    // throws InvalidOperationException

#133 – An Array’s Length Is Fixed

The size of standard arrays in C# is fixed–once instantiated, you can’t change the number of elements in the array. If you need a list of objects to which you can add or remove elements, you should use one of the classes in the System.Collections namespace.  Specifically, the ArrayList type allows creating a collection of objects that can grow or shrink dynamically.

#132 – Arrays That Are Both Multidimensional and Jagged

Jagged arrays are different than multidimensional arrays.  Multidimensional arrays have a rank greater than one, with a separate indexer and a size for each rank.  Jagged arrays are just an array of arrays.

You can create an array which is both jagged and multidimensional.  Here’s an example (a two-dimensional array of arrays).

 // Multidimensional / jagged array.  E.g. store array
 //   of phone call objects for each day of the week,
 //   each hour of the day.
 PhoneCall[,][] weeklyCallLog = new PhoneCall[7, 24][];

 // Record 2 calls for Monday between 8-9 AM
 weeklyCallLog[1 ,8] = new PhoneCall[2];
 weeklyCallLog[1, 8][0] = thisCall;
 weeklyCallLog[1, 8][1] = thatCall;

Here’s another example (an array of two-dimensional arrays):

 // public enum ChessPiece { Empty, Knight, Rook, Etc };
 ChessPiece[][,] chessGame = new ChessPiece[100][,];
 chessGame[0] = new ChessPiece[8, 8];

#131 – Arrays Derive from System.Array

In C#, all arrays derive from the abstract class System.Array.  You can directly create objects of type System.Array, but must create arrays using the syntax for declaring and instantiating arrays built into the C# language.

Because arrays inherit from System.Array, all arrays inherit certain methods and properties from the Array class.

For example, every array has the properties:

  • Length – Total number of elements, across all dimensions of the array
  • Rank – Number of dimensions in the array
 int[] nums = new int[4];
 int[,] nums2D = new int[2, 3];
 int[][] numsJagged = new int[2][];
 numsJagged[0] = new int[2];
 numsJagged[1] = new int[3];

 int n = nums.Length;    // 4
 n = nums.Rank;          // 1

 n = nums2D.Length;      // 6
 n = nums2D.Rank;        // 2

 n = numsJagged.Length;  // 2
 n = numsJagged.Rank;    // 1

Note that for the jagged array, because the array  is really an array of arrays, Length and Rank operate on the outer array, which is just a 2-element one-dimensional array.

#130 – Default Values of Array Elements

After declaring and instantiating an array, all of its elements take on default values.  The default value for all numeric types is 0 and for all reference types is null.  For enum types, the default value will be the element that has a value of 0–typically the first item listed in the enum.

 float[] nums = new float[4];
 float f1 = nums[0];    // 0.0

 Cat[] pack = new Cat[5];
 Cat c1 = pack[0];      // null

 Days[] someDays = new Days[4];
 Days thatDay = someDays[2];   // Sunday (1st in list)

The same rule applies for default values in a multi-dimensional array.  Each element is 0-valued or null.

 int[,] nums = new int[2, 3];
 int aNum = nums[1, 2];          // 0

With jagged arrays, you typically only instantiate the first dimension.  Elements of that dimension are null.

 int[][] jagged = new int[3][];
 object o = jagged[0];    // null
 int n1 = jagged[0][0];   // Error: NullReferenceException

 jagged[0] = new int[10];
 int n2 = jagged[0][2];    // 0