12,350,735 members (35,401 online)

19.1K views
202 downloads
16 bookmarked
Posted

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; } } } ```

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

 Software Developer (Senior) Takamomto, LLC United States
I have been doing database related programming in the financial services industry for over 20 years on various platforms. I used to be a UNIX Sybase DBA but now prefer programming in the .NET environment using C# and SQL Server.

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.160621.1 | Last Updated 30 Mar 2011
Article Copyright 2011 by Tony Zackin
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid