12,951,548 members (51,364 online)

#### Stats

21.2K views
16 bookmarked
Posted 19 Mar 2011

# Using LINQ and Extension Methods in C# to Sort Vectors and Two-Dimensional Arrays

, 30 Mar 2011 CPOL
This article explains and shows examples of using LINQ and extension methods for array sorting
 ```﻿using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace TwoDimArraySort { /// /// This class is used to modify the default sorting order /// /// The type of objects to compare class Comparer : IComparer { public int Compare(T x, T y) { if (typeof(T) == typeof(int)) { int ix = (int)(object)x; int iy = (int)(object)y; return ix.CompareTo(iy); // <0 => x is less than y, 0 => x equals y, >0 => x is greater than y. } else if (typeof(T) == typeof(string)) { string sx = (string)(object)x; string sy = (string)(object)y; return String.CompareOrdinal(sx, sy); // Use CompareOrdinal to be case-sensitive } else return 0; } } static class Program { static internal Dictionary dict; static void Main(string[] args) { // Use this to sort numbers based on their spelling #region Dictionary definition (even numbers are capitalized) dict = new Dictionary(10); dict.Add(0, "Zero"); dict.Add(1, "one"); dict.Add(2, "Two"); dict.Add(3, "three"); dict.Add(4, "Four"); dict.Add(5, "five"); dict.Add(6, "Six"); dict.Add(7, "seven"); dict.Add(8, "Eight"); dict.Add(9, "nine"); #endregion // Create a jagged array int[][] ja = new int[3][]; ja[0] = new int[] { 9, 7, 3, 8, 0, 6, 1, 2 }; ja[1] = new int[] { 8, 6, 4, 3 }; ja[2] = new int[] { 6, 9 }; // Create a vector int[] v = ja[0]; v.Show("v", "\r\nInitial vector"); // To order a sequence by the values of the elements themselves, specify the identity function (x => x) #region Initial vector output // ***** // v[0] = 9, v[1] = 7, v[2] = 3, v[3] = 8, v[4] = 0, v[5] = 6, v[6] = 1, v[7] = 2, // ***** #endregion v.OrderBy(x => x).ToArray().Show("ovi", "\r\nSorted by integer value"); #region Sorted by integer value output // ***** // ovi[0] = 0, ovi[1] = 1, ovi[2] = 2, ovi[3] = 3, ovi[4] = 6, ovi[5] = 7, ovi[6] = 8, ovi[7] = 9, // ***** #endregion // Use the function F(x) to convert the number argument x to a string based on its spelling v.OrderBy(x => F(x)).ToArray().Show("ovci", "\r\nCase insensitive ordering of number's spelling"); #region Case insensitive ordering of number's spelling output // ***** // ovci[0] = 8, ovci[1] = 9, ovci[2] = 1, ovci[3] = 7, ovci[4] = 6, ovci[5] = 3, ovci[6] = 2, ovci[7] = 0, // ***** #endregion // Use the string version of the generic Comparer class to order the results in case sensitive order v.OrderBy(x => F(x), new Comparer()).ToArray().Show("ovcs", "\r\nCase sensitive ordering -- even numbers first"); #region Case sensitive ordering -- even numbers first output // ***** // ovcs[0] = 8, ovcs[1] = 6, ovcs[2] = 2, ovcs[3] = 0, ovcs[4] = 9, ovcs[5] = 1, ovcs[6] = 7, ovcs[7] = 3, // ***** #endregion ja.Show("ja", -999, "\r\n\r\nInitial jagged array"); #region Initial jagged array output // ***** // ja[0][0] = 9, ja[0][1] = 7, ja[0][2] = 3, ja[0][3] = 8, ja[0][4] = 0, ja[0][5] = 6, ja[0][6] = 1, ja[0][7] = 2, // ja[1][0] = 8, ja[1][1] = 6, ja[1][2] = 4, ja[1][3] = 3, // ja[2][0] = 6, ja[2][1] = 9, // ***** #endregion // EnumerateInnerVectors returns an enumeration of the vectors representing the "rows" of the jagged array // Argument 1 specifies to pad each row to 8 elements with a value of -999 (representing a missing value) // The lambda expression x => x[1] orders the enumerated vectors based on the second column value int[][] oa = ja.EnumerateInnerVectors(8, -999).OrderByDescending(x => x[1]).ToArray(); oa.Show("oja1d", -999, "\r\nJagged array ordered in descending order on the second column"); #region Jagged array ordered in descending order on the second column output // ***** // oja1d[0][0] = 6, oja1d[0][1] = 9, oja1d[0][2] = -, oja1d[0][3] = -, oja1d[0][4] = -, oja1d[0][5] = -, oja1d[0][6] = -, oja1d[0][7] = -, // oja1d[1][0] = 9, oja1d[1][1] = 7, oja1d[1][2] = 3, oja1d[1][3] = 8, oja1d[1][4] = 0, oja1d[1][5] = 6, oja1d[1][6] = 1, oja1d[1][7] = 2, // oja1d[2][0] = 8, oja1d[2][1] = 6, oja1d[2][2] = 4, oja1d[2][3] = 3, oja1d[2][4] = -, oja1d[2][5] = -, oja1d[2][6] = -, oja1d[2][7] = -, // ***** #endregion // Order the rows based on the value of the fifth column of each vector ja.EnumerateInnerVectors(5, -999).OrderBy(x => x[4]).ToArray() .Show("oj4a", -999, "\r\nJagged array ordered in ascending order on the fifth column"); #region Jagged array ordered in ascending order on the fifth column output // ***** // oj4a[0][0] = 8, oj4a[0][1] = 6, oj4a[0][2] = 4, oj4a[0][3] = 3, oj4a[0][4] = -, // oj4a[1][0] = 6, oj4a[1][1] = 9, oj4a[1][2] = -, oj4a[1][3] = -, oj4a[1][4] = -, // oj4a[2][0] = 9, oj4a[2][1] = 7, oj4a[2][2] = 3, oj4a[2][3] = 8, oj4a[2][4] = 0, oj4a[2][5] = 6, oj4a[2][6] = 1, oj4a[2][7] = 2, // ***** #endregion // Sorting a two-dimensional array int[,] array = new int[3, 3] { { 9, 1, 4 }, { 4, 5, 1 }, { 7, 3, 8 } }; array.Show("array", "\r\nInitial 2 dimensional array"); #region Initial 2 dimensional array output // ***** // array[0][0] = 9, array[0][1] = 1, array[0][2] = 4, // array[1][0] = 4, array[1][1] = 5, array[1][2] = 1, // array[2][0] = 7, array[2][1] = 3, array[2][2] = 8, // ***** #endregion int[,] sortedByFirstElement = array.OrderBy(x => x[0]); sortedByFirstElement.Show("array", "\r\nArray sorted by first element"); #region Array sorted by first element output // ***** // array[0][0] = 4, array[0][1] = 5, array[0][2] = 1, // array[1][0] = 7, array[1][1] = 3, array[1][2] = 8, // array[2][0] = 9, array[2][1] = 1, array[2][2] = 4, // ***** #endregion int[,] sortedBySecondElement = array.OrderBy(x => x[1]); sortedBySecondElement.Show("array", "\r\nArray sorted by second element"); #region Array sorted by second element output // ***** // array[0][0] = 9, array[0][1] = 1, array[0][2] = 4, // array[1][0] = 7, array[1][1] = 3, array[1][2] = 8, // array[2][0] = 4, array[2][1] = 5, array[2][2] = 1, // ***** #endregion int[,] sortedByThirdElement = array.OrderBy(x => x[2]); sortedByThirdElement.Show("array", "\r\nArray sorted by third element"); #region Array sorted by third element output // ***** // array[0][0] = 4, array[0][1] = 5, array[0][2] = 1, // array[1][0] = 9, array[1][1] = 1, array[1][2] = 4, // array[2][0] = 7, array[2][1] = 3, array[2][2] = 8, // ***** #endregion } /// /// This function is used to sort numbers from 0-9 based on their spelling /// /// The input number /// The spelling of the number static string F(int n) { return dict[n]; // dict[0] = "Zero", dict[1] = "one", dict[2] = "Two", etc. } /// /// This extension method is used to display a vector /// /// The vector to display /// The name of the vector, e.g., if "v" is the name the /// display will be v[0] = n1, v[1] = n2, ... /// Optional text to describe the output. /// The minimum width of each output column. static void Show(this int[] array, string name, string title = "", int width = 6) { Debug.WriteLine(title + "\r\n*****"); for (int i = 0; i <= array.GetUpperBound(0); i++) Debug.Write(name + "[" + i.ToString() + "] = " + (array[i].ToString() + ", ").PadRight(width)); Debug.WriteLine("\r\n*****"); } /// /// This extension method is used to display a two-dimensional jagged array /// /// The jagged array to display /// The name of the array, e.g., if "ja" is the name the /// display will be ja[0][0] = n1, ja[0][1] = n2, ... /// An integer value indicating missing data in a jagged array /// which will be replaced by a special character. /// Optional text to describe the output. /// The minimum width of each output column. static void Show(this int[][] array, string name, int missingValue, string title = "", int width = 6) { Debug.WriteLine(title + "\r\n*****"); for (int i = 0; i <= array.GetUpperBound(0); i++) { for (int j = 0; j <= array[i].GetUpperBound(0); j++) Debug.Write(name + "[" + i.ToString() + "][" + j.ToString() + "] = " + (array[i][j].AsString(missingValue) + ", ").PadRight(width)); Debug.WriteLine(""); } Debug.WriteLine("*****"); } /// /// This extension method is used to display a two-dimensional array /// /// The array to display /// The name of the array, e.g., if "a" is the name the /// display will be a[0,0] = n1, a[0,1] = n2, ... /// Optional text to describe the output. /// The minimum width of each output column. static void Show(this int[,] array, string name, string title = "", int width = 6) { Debug.WriteLine(title + "\r\n*****"); for (int i = 0; i <= array.GetUpperBound(0); i++) { for (int j = 0; j <= array.GetUpperBound(1); j++) Debug.Write(name + "[" + i.ToString() + "][" + j.ToString() + "] = " + (array[i, j].ToString() + ", ").PadRight(width)); Debug.WriteLine(""); } Debug.WriteLine("*****"); } /// /// This extension method is used to convert an integer to a string replacing "missing values" /// (arbitrarily) to a minus sign. /// /// The integer value to convert. /// The value to be replaced by the minus sign. /// The string value of the number or a minus sign. static string AsString(this int n, int missingValue) { if (n == missingValue) return "-"; else return n.ToString(); } /// /// Enumerates the "inner" vectors of a two dimensional jagged array. /// /// The type of the jagged two-dimensional array. /// The jagged two-dimensional array. /// An enumeration of T[] consisting of the inner vectors of the jagged array. /// Note that if this is used with OrderBy, the order-by column must exist in all inner vectors. private static IEnumerable EnumerateInnerVectors(this T[][] source) { for (int i = 0; i <= source.GetUpperBound(0); i++) yield return source[i]; } /// /// Enumerates the "inner" vectors of a two dimensional jagged array. Short vectors will be padded to a specified minimum length. /// /// The type of the jagged two-dimensional array. /// The jagged two-dimensional array. /// The minimum length of an inner vector. Rows will be padded with the default value to this length. /// A value of type T to be used for short rows. /// An enumeration of T[] consisting of the inner vectors of the jagged array padded with missingValue values if necessary. private static IEnumerable EnumerateInnerVectors(this T[][] source, int minLength, T missingValue) { for (int i = 0; i <= source.GetUpperBound(0); i++) { if (source[i].Length >= minLength) { yield return source[i]; continue; } T[] v = new T[minLength]; for (int j = 0; j < minLength; j++) { if (j > source[i].Length - 1) v[j] = missingValue; else v[j] = source[i][j]; } yield return v; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // The following code was written by Andrew Rissing (http://www.codeproject.com/script/Membership/View.aspx?mid=1431085) // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// Orders the two dimensional array by the provided key in the key selector. /// /// The type of the source two-dimensional array. /// The source two-dimensional array. /// The selector to retrieve the column to sort on. /// A new two dimensional array sorted on the key. public static T[,] OrderBy(this T[,] source, Func keySelector) { return source.ConvertToSingleDimension().OrderBy(keySelector).ConvertToMultiDimensional(); } /// /// Orders the two dimensional array by the provided key in the key selector in descending order. /// /// The type of the source two-dimensional array. /// The source two-dimensional array. /// The selector to retrieve the column to sort on. /// A new two dimensional array sorted on the key. public static T[,] OrderByDescending(this T[,] source, Func keySelector) { return source.ConvertToSingleDimension().OrderByDescending(keySelector).ToArray().ConvertToMultiDimensional(); } /// /// Converts a two dimensional array to single dimensional array. /// /// The type of the two dimensional array. /// The source two dimensional array. /// The repackaged two dimensional array as a single dimension based on rows. private static IEnumerable ConvertToSingleDimension(this T[,] source) { T[] arRow; for (int row = 0; row < source.GetLength(0); ++row) { arRow = new T[source.GetLength(1)]; for (int col = 0; col < source.GetLength(1); ++col) arRow[col] = source[row, col]; yield return arRow; } } /// /// Converts a collection of rows from a two dimensional array back into a two dimensional array. /// /// The type of the two dimensional array. /// The source collection of rows to convert. /// The two dimensional array. private static T[,] ConvertToMultiDimensional(this IEnumerable source) { T[,] twoDimensional; T[][] arrayOfArray; int numberofColumns; arrayOfArray = source.ToArray(); numberofColumns = (arrayOfArray.Length > 0) ? arrayOfArray[0].Length : 0; twoDimensional = new T[arrayOfArray.Length, numberofColumns]; for (int row = 0; row < arrayOfArray.GetLength(0); ++row) for (int col = 0; col < numberofColumns; ++col) twoDimensional[row, col] = arrayOfArray[row][col]; return twoDimensional; } } } ```

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.