How to sort Jagged and Rectangular Arrays in C# 17th Dec 2022

sorting

In the previous blog, we saw what are Arrays in general. Link to that blog Array in general and how to sort 1D array in C Sharp.We also saw how to sort 1-Dimensional Array

In the previous blog we saw,there was nothing fancy. It was just Array's inbuilt sort method doing the trick for us. Now, let's discuss sorting of Jagged and Rectangular Arrays.

Sorting Jagged Arrays

Lets sort Jagged Arrays based on "column". I will show you there methods to sort

    Scenarios:
  • Sort by first column
  • Sort by second column
  • Sort first non matching column

Sort by First Column


                //a is the array we want to sort by first column.Basically,
                // I want output to be like {13,11,19},{27,25,99},{33,12,22}
                // & {33,12,21}
                int[][] a = new int[][] {
                new int[]{13,11,19},
                new int[]{33,12,22},
                new int[]{33,12,21},
                new int[]{27,25,99},
                };
                SortArray.SortJaggedArray(a,"FIRST");

            

SortArray is a custom class I wrote. It exposes methods to be called by our Program.cs.Below, you can see how it calls appropriate functions to sort on column,based on columnNumber.


              public static int[][] SortJaggedArray(int[][] a,string columnNumber)
              {
                  CustomSortComparerOptions cs = new CustomSortComparerOptions();
                  if(columnNumber.ToUpper().Equals("FIRST"))
                      Array.Sort(a, CustomSortComparerOptions.SortByFirstColumn());
                  if (columnNumber.ToUpper().Equals("SECOND"))
                      Array.Sort(a, CustomSortComparerOptions.SortBySecondColumn());
                  if (columnNumber.ToUpper().Equals("FIRST-NON-MATCHING"))
                      Array.Sort(a, CustomSortComparerOptions.SortByFirstNotEqualColumn());
                  return a;
              }
            

CustomSortComparerOptions is another class I wrote which has logic to sort the arrays. It has 3 helper classes internally

  • SortByFirstColumnHelper
  • SortBySecondColumnHelper
  • SortByFirstNotEqualColumnHelper(for our 3 scenarios)

                    public static IComparer SortByFirstColumn()
                    {
                        return (IComparer)new SortByFirstColumnHelper();
                    }
                    private class SortByFirstColumnHelper : IComparer
                    {
                        int IComparer.Compare(object? x, object? y)
                        {
                        int[] a1 = (int[])x;
                        int[] a2 = (int[])y;
                        return (a1[0].CompareTo(a2[0]));
                        }
                    }
            
Output: As expected - sorted by first column

                    13 11 19
                    27 25 99
                    33 12 22
                    33 12 21
                

Sort by Second Column

Here, I have another array which I want to sort by "Second Column"


                //a is the array we want to sort by second column
                //Output expected is {13,11,19},{33,12,22},{33,12,21},{27,25,99}
                int[][] a = new int[][] {
                new int[]{27,25,99},
                new int[]{33,12,22},
                new int[]{13,11,19},
                new int[]{33,12,21}
                };
            SortArray.SortJaggedArray(a);
            

SortArray class still remain the same except the fact that it now calls my SortBySecondColumn function of CustomSortComparerOptions class.

CustomSortComparerOptions has SortBySecondColumnHelper() and SortBySecondColumn() below


                public static IComparer SortBySecondColumn()
                {
                    return (IComparer)new SortBySecondColumnHelper();
                }
                private class SortBySecondColumnHelper : IComparer
                {
                    int IComparer.Compare(object? x, object? y)
                    {
                    int[] a1 = (int[])x;
                    int[] a2 = (int[])y;
                    return (a1[1].CompareTo(a2[1]));
                    }
                }
            
Output: As expected - sorted by second column

                    13 11 19
                    33 12 22
                    33 12 21
                    27 25 99
            

Sort by first non matching column

Here, I am using the same array as we saw in our second scenario above


                //a is the array we want to sort by first non matching column
                //expected output : {13,11,19},{27,25,99},{33,12,21},33,12,22}
                int[][] a = new int[][] {
                new int[]{27,25,99},
                new int[]{33,12,22},
                new int[]{13,11,19},
                new int[]{33,12,21}
                };
            SortArray.SortJaggedArray(a);
            

SortArray still remain the same except the fact that it now calls my SortByFirstNotEqualColumn() function of CustomSortComparerOptions class.

CustomSortComparerOptions - SortByFirstNotEqualColumnHelper() and SortByFirstNotEqualColumn() methods below:


                public static IComparer SortByFirstNotEqualColumn()
                {
                    return (IComparer)new SortByFirstNotEqualColumnHelper();
                }
                private class SortByFirstNotEqualColumnHelper : IComparer
                {
                    int IComparer.Compare(object x, object y)
                    {
                        int[] a1 = (int[])x;
                        int[] a2 = (int[])y;
                        for (var i = 0; i < a1.Length; i++)
                        {
                          for (var j = i; i < a2.Length; j++)
                          {
                          if (a1[i] != (a2[j]))
                          {
                          return (a1[i].CompareTo(a2[j]));
                          }
                          else
                          {
                          break;
                          }
                        }
                      }
                        return -1;
                    }
                 }
                    
Output we receive is as expected(sorted by first non matching column column):

For eg, array with values {33,12,22} and {33,12,21}, has first 2 columns same i.e 33 and 12, therefore, in this case, column 3 will decide the sorting and therefore, array with third column value 21 is printed before array with third column value 22


                13 11 19
                27 25 99
                33 12 21
                33 12 22
            

Sorting Rectangular Arrays

Rectangular arrays are also called Multidimensional arrays.These arrrays are uniform arrays.Eg below


              int[,] a1 = new int[,] { { 12, 01 }, { 10,13 },   { 19, 27 } ,{ 13, 11 }};
            

Above is a uniform 2d array.You can't assign a 1d array to a row or column. Point to remember is that, you must index both the row and column, which will eventually get you down to a "single int" in this case.

Unlike Jagged arrays, which is array of arrays,therefore we can reference the first dimension as an array by itself. If you are wondering what it means,then see the code below


                //2dArray- Jagged Array
                int[][] a = new int[][] {
                new int[]{27,25,99},
                new int[]{33,12,22},
                new int[]{13,11,19},
                new int[]{33,12,21}
                };

                int[] aa = new int[3] {10,12,13};
                a[0] = aa;//replaced first element of a
                Console.WriteLine(a);// will print [{10,12,13},{33,12,22},{13,11,19},{33,12,21}]
           

Since you can do above with Jagged arrays, when you call "Array.Sort",you can swap array references as wanted in response to the values returned by the IComparer.Compare method.

a1 array below, declares a rectangular 4-by-2 two-dimensional array, initializing it with numbers {12,01}, {10,13}, { 19, 27 } and { 13, 11 }


              Program.cs
              
              int[,] a1 = new int[,] { { 12, 01 }, { 10, 13 }, { 19, 27 }, { 13, 11 } };
            
          

Remember how we sorted Jagged Arrays.It was pretty simple to sort Jagged Arrays,however, sorting rectangular arrays are bit more trickier.You cannot "swap rows" in a rectangular array because the entire array in itself is a "one object" rather than an array of one-dimensional arrays.Having said that, you can still sort a rectangular array.To sort a rectangular array, you have to create a second one-dimensional array, which will contain the row numbers of the rectangular array. I created "idTrackingArray" above.The "IComparer.Compare" method will use the passed row numbers to index into the rectangular array and sort the items.

Below is Program.cs

  
              int[,] a1 = new int[,] { { 12, 01 }, { 10, 13 }, { 19, 27 }, { 13, 11 } };
              int[] idTrackingArray = new int[] { 0, 1, 2, 3 };
              a1 = SortArray.SortMultiDimensionalArray(a1, idTrackingArray,"FIRST");
              PrintOutputFor2DRectangularArray(idTrackingArray, a1);
              Console.WriteLine("output for sort by FIRST column");
              PrintOutputFor2DRectangularArray(idTrackingArray, a1);
              Console.WriteLine("-----RESET-----");              
              a1 = new int[,] { { 12, 01 }, { 10, 13 }, { 19, 27 }, { 13, 11 } };//reset
              PrintOutputFor2DRectangularArray(idTrackingArray, a1);
              a1 = SortArray.SortMultiDimensionalArray(a1, idTrackingArray, "SECOND");
              Console.WriteLine("output for sort by SECOND column");
              PrintOutputFor2DRectangularArray(idTrackingArray, a1);
              Console.WriteLine("-----RESET----");

SortArray class I wrote, exposes a SortMultiDimensionalArray() function.It basically calls SortByFirstColumn() or SortBySecondColumn() on RectangularComparerOptions instance based on "columnNumber"


              public static int[,] SortMultiDimensionalArray(int[,] a,int[] trackerArray, string columnNumber)
              {            
                  RectangularComparerOptions rs = new RectangularComparerOptions(a);
                  if (columnNumber.ToUpper().Equals("FIRST"))
                      Array.Sort(trackerArray, rs.SortByFirstColumn(a));
                  if (columnNumber.ToUpper().Equals("SECOND"))
                      Array.Sort(trackerArray, rs.SortBySecondColumn(a));
                  return a;
              }

                

Below is the implementation of the RectangularComparerOptions. It has "SortByFirstColumn" and "SortBySecondColumn" methods. Call methods based on what you want to perform.


                    namespace SortArrayEg
                    {
                      public class RectangularComparerOptions
                      {
                        // maintain a reference to the 2-dimensional array being sorted
                        public int[,] sortArray;

                      // constructor initializes the sortArray reference
                      public RectangularComparerOptions(int[,] theArray)
                      {
                        sortArray = theArray;
                      }
                      class SortByFirstColumnHelper : IComparer
                      {
                        RectangularComparerOptions r_;
                        public SortByFirstColumnHelper()
                      {
                      }

                      public SortByFirstColumnHelper(RectangularComparerOptions r1)
                      {
                        r_=r1;
                      }

                      public int Compare(object x, object y)
                      {
                        // x and y are integer row numbers into the sortArray
                        int i1 = (int)x;
                        int i2 = (int)y;
                        // compare the items in the sortArray
                        return (r_.sortArray[i1, 0].CompareTo(r_.sortArray[i2, 0]));
                      }
                      }
                      class SortBySecondColumnHelper : IComparer
                      {
                        RectangularComparerOptions r_;
                        public SortBySecondColumnHelper()
                        {
                        }
                        public SortBySecondColumnHelper(RectangularComparerOptions r1)
                        {
                        r_ = r1;
                        }

                        public int Compare(object x, object y)
                        {
                        // x and y are integer row numbers into the sortArray
                        int i1 = (int)x;
                        int i2 = (int)y;
                        // compare the items in the sortArray
                        return (r_.sortArray[i1, 1].CompareTo(r_.sortArray[i2, 1]));
                        }
                      }

                      public IComparer SortByFirstColumn(int[,] a)
                      {
                      return (IComparer)new SortByFirstColumnHelper(this);
                      }
                      public IComparer SortBySecondColumn(int[,] a)
                      {
                      return (IComparer)new SortBySecondColumnHelper(this);
                      }
                    }
                }
                
              

If you call SortByFirstColumn() function the output would be


                  10 13
                  12 1
                  13 11
                  19 27
          

If you call SortBySecondColumn() function the output would be


                12 1
                13 11
                10 13
                19 27
              

One thing I would like to mention is that, sometimes it's easier to convert a rectangular array into a Jagged array and then perform the sort. Let's see below how to convert

Convert a rectangular array into a Jagged array


                  public static int [][] ConvertMultiDimensionalArrayToJaggedArray(int[,] a)
                  {
                    int[][] myJaggedArray = new int[a.GetUpperBound(0) + 1][];
                    for (int i = 0; i < myJaggedArray.Length; i++)
                    myJaggedArray[i] = Enumerable.Range(0, a.GetUpperBound(1) + 1).Select(k => a[i, k]).ToArray();
                    return myJaggedArray;
                  }
          
Conclusion.

To conclude,I hope you would have got a better understanding on how to Sort Rectangular arrays and Jagged arrays.

GitHub Repo Link

Email me at "techspacedeck@gmail.com" incase you have queries. Alternatively, you can fill the "CONTACT" form or drop a comment below

Did you like the blog or have questions, please add your comments