Introduction
Almost every program I have created needs a method for sorting a two-dimensional array by column one in the selected sort order, then by column two in the selected sort order, and then by column three in the selected sort order ... then by column n in the selected sort order.
Sort two-dimensional arrays
For sorting two-dimensional arrays containing different types of values, integers, strings, booleans, etc., I have used the DataGridView class and its DataGridViewSort event handler. It is easy to manipulate data in any way and offers fast sorting as well.
But sometimes, it is not possible to implement such a solution. So, I have made the decision to try to write my own universal method for sorting 2D arrays that could be used for sorting arrays in any future program that I am going to write.
After a while, I have written this method.
/// <summary>
/// Sorts a two-dimensional array of strings by selected columns in selected sort order using the Selection Sort Algorithm.
/// </summary>
/// <param name="array">
/// Two-dimensional array of strings containing values that are going to be sorted.
/// </param>
/// <param name="sort_directive">
/// Two-dimensional array of integers. First column contains the order of the column indexes
/// by which the array will be sorted. Second column contains column sort order.
/// Sort order for each column is defined by integer values:
/// -1 - sort column values in Descending sort order
/// 0 - column is not going to be sorted
/// 1 - sort column values in Ascending sort order
/// </param>
/// <returns>
/// Sorted array by selected columns in selected sort order.
/// </returns>
public string[,] SortStringArray(string[,] array, int[,] sort_directive)
{
int arrayRows = array.GetLength(0);
int arrayColumns = array.Length / arrayRows;
int sortDirectiveColumns = sort_directive.GetLength(0);
for (int i = 0; i < arrayRows - 1; i++)
{
for (int j = i + 1; j < arrayRows; j++)
{
for (int c = 0; c < sortDirectiveColumns; c++)
{
int columnToSort = sort_directive[c, 0];
int sortOrder = sort_directive[c, 1];
int comparisonResult = array[i, columnToSort].CompareTo(array[j, columnToSort]);
if ((sortOrder == -1 && comparisonResult < 0) ||
(sortOrder == 1 && comparisonResult > 0))
{
for (int d = 0; d < arrayColumns; d++)
{
string temp = array[j, d];
array[j, d] = array[i, d];
array[i, d] = temp;
}
break;
}
else if ((sortOrder == -1 && comparisonResult > 0) ||
(sortOrder == 1 && comparisonResult < 0))
{
break;
}
}
}
}
return array;
}How did I develop the Sort method?
The first decision was that the 2D array should strictly be the type of string.
Since any other type of data (int, double, float, decimal, char, boolean, ...) can be represented as a string value, and because of that, the 2D array type of string could contain diverse types of data that could be easily manipulated and sorted.
Important
Data stored inside the array type of string are always represented (memorized) as a type of String. When sorting, all data are compared as strings and numbers. If there is a need to sort numbers, it is necessary to adjust the format of data so that the sort routine returns the correct result.
numerical data as strings | numerical data formated for sorting as number values | sorted correctly as numbers |
"1" | "0001" | "0001" |
"10" | "0010" | "0003" |
"214" | "0214" | "0004" |
"3" | "0003" | "0005" |
"4" | "0004" | "0010" |
"5" | "0005" | "0214" |
"1024" | "1024" | "1024" |
numerical data as strings | numerical data not formated for sorting as number values | sorted correctly as strings |
"1" | "1" | "1" |
"10" | "10" | "10" |
"214" | "214" | "1024" |
"3" | "3" | "214" |
"4" | "4" | "3" |
"5" | "5" | "4" |
"1024" | "1024" | "5" |
Example of formatting numerical data.
int numerical_data = 100;
string format = "000000";
string formated_data = numerical_data.ToString(format);Result of formatting.
Numerical data | Formated data |
100 | 000100 |
1000 | 001000 |
10000 | 010000 |
The name of the 2D array inside the program shall be TABLE.
Declaration of TABLE with 10 rows and 10 columns, max 100 elements.
int rows = 10;
int columns = 10;
string [,] TABLE = new string[rows,columns];The second decision was to use a 2D array type of integer for storing TABLE sort directives.
A simple sort directive looks like this.
Sort TABLE by Column One in Ascending sort order.
As shown, the sort directive consists of the selected TABLE column index and its sort order.
So this array should have only two columns.
The first column shall contain a selected column index.
The second column contains column sort order defined by integer values.
- 1: Sort column values in Descending sort order
0: The column is not going to be sorted
1: Sort column values in Ascending sort order
The number of rows depends on how many sort directives are entered by the user.
The name of the 2D array inside the program shall be SORT_DIRECTIVE.
Declaration of SORT_DIRECTIVE,
int rows = number of sort directives;
int columns = 2;
int [,] SORT_DIRECTIVE = new string[rows,columns];Example of sort directive and SORT_DIRECTIVE element values
TABLE has seven rows and three columns,
Sort TABLE by Column One in Ascending sort order, then by
Column Two in Descending sort order then by
Column Three in Ascending sort order.
SORT_DIRECTIVE
Column Index | Sort Order |
1 | 1 |
2 | -1 |
3 | 1 |
The third and final decision was the selection of the Sort Algorithm.
I have decided to use the Selection Sort Algorithm for its simplicity of implementation. Also, it is fast enough for a small amount of data, up to 1000 records.
How does SORT_DIRECTIVE work?
Create and fill the TABLE with data. Be careful if some column should contain numbers. Numbers must be specially formatted for sorting as described in the important notice above.
// Create and fill TABLE
string[,] TABLE = new string[7, 3]
{
{ "John", "Porter", "1234 Oak street, Pensacola, FL 32503" },
{ "John", "Porter", "1891 3rd Street North Westlake, OH 44145" },
{ "William", "Patterson", "4534 Virginia Street Dallas, GA 30132" },
{ "Marry", "Cortez", "7642 Fairview Avenue Milwaukee, WI 53204" },
{ "John", "Patterson", "1368 Street Road Morristown, NJ 07960" },
{ "Elizabet", "Cortez", "3698 Cedar Avenue Saratoga Springs, NY 12886" },
{ "Marry", "Mosley", "4575 11th Street Sacramento, CA 95820" }
};
Then, create and fill SORT_DIRECTIVE.
//
// Table SORT DIRECTIVE contains order of columns
// by which array is going to be sorted and sort order
// for each selected column
//
// 0 - do not sort column
// -1 - sort in Descending order
// 1 - sort in Ascending order
//
int [,] SORT_DIRECTIVE=new int[3,2]
{
{0, 1},
{1, -1},
{2, 1}
}; Call method.
//
// Call sort method
//
TABLE = Sort_String(TABLE,SORT_DIRECTIVE); When finished, the method returns a sorted array TABLE by values inside SORT_DIRECTIVE.
//
// Print sorted TABLE
//
Console.WriteLine();
Console.WriteLine(" SORTED TABLE");
Console.WriteLine(" --------------");
Console.WriteLine();
for(int n=0;n<7;n++)
{
Console.WriteLine(" {0,-10}{1,-10}{2,-10}",TABLE[n,0],TABLE[n,1],TABLE[n,2]);
}
Console.WriteLine(" --------------");
//Here is the program's screenshot.

Note. The names and addresses shown in the picture are fictional.
Conclusion
For sorting up to a thousand rows filled with data, this method is almost as fast as DataGridView with its SortEventHandler. If there is a need for sorting more data than that, perhaps by implementing a faster sort algorithm, things would be better. This method can easily be changed to sort 2D arrays of any type.
Sort_String
Sort_Int
Sort_Double
Sort_Decimal
Sort_Float
The name of the method shows what is the type of array that is going to be sorted.
class Sort_2D_Array
{
/// <summary>
/// Sorts two dimensional array type of string,
/// by selected culumns, in selected sort order.
/// Selection Sort Algorithm is implemented
/// for sorting values inside array.
/// </summary>
/// <param name="array">
/// Two dimensional array, type of string,
/// contaning values that are going to be sorted.
/// </param>
/// <param name="sort_directive">
/// Two dimensional array, type of int.
/// First column contains the order of the column indexes
/// by which the array will be sorted.
/// Second column contains column sort order.
/// Sort order for each column is defined by ineger values :
/// -1 - sort column values in Descending sort order
/// 0 - column is not going to be sorted
/// 1 - sort column values in Ascending sort order
/// </param>
/// <returns>
/// Sorted array by selected columns in selected sort order.
/// </returns>
public string[,] Sort_String(string [,] array, int [,] sort_directive)
{
// number of rows iside array
int array_rows = array.GetLength(0);
// number of columns inside array
int array_columns = array.Length/array_rows;
// number of columns to be sorted
int sort_directive_columns = sort_directive.GetLength(0);
//
for(int i=0;i<array_rows-1;i++)
{
for(int j=i+1;j<array_rows;j++)
{
for(int c=0;c<sort_directive_columns;c++)
{
//
// sort array values in descending sort order
//
if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
{
//
// if values are in ascending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
string h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
break;
//
// sort array values in ascending sort order
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
{
//
// if values are in descending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
string h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
break;
//
// if values are equal
// select next sort directive
//
}
}
}
//
// return sorted array
//
return array;
}
/// <summary>
/// Sorts two dimensional array type of int,
/// by selected culumns, in selected sort order.
/// Selection Sort Algorithm is implemented
/// for sorting values inside array.
/// </summary>
/// <param name="array">
/// Two dimensional array, type of int,
/// contaning values that are going to be sorted.
/// </param>
/// <param name="sort_directive">
/// Two dimensional array, type of int.
/// First column contains the order of the column indexes
/// by which the array will be sorted.
/// Second column contains column sort order.
/// Sort order for each column is defined by ineger values :
/// -1 - sort column values in Descending sort order
/// 0 - column is not going to be sorted
/// 1 - sort column values in Ascending sort order
/// </param>
/// <returns>
/// Sorted array by selected columns in selected sort order.
/// </returns>
public int[,] Sort_Int(int [,] array, int [,] sort_directive)
{
// number of rows iside array
int array_rows = array.GetLength(0);
// number of columns inside array
int array_columns = array.Length/array_rows;
// number of columns to be sorted
int sort_directive_columns = sort_directive.GetLength(0);
//
for(int i=0;i<array_rows-1;i++)
{
for(int j=i+1;j<array_rows;j++)
{
for(int c=0;c<sort_directive_columns;c++)
{
//
// sort array values in descending sort order
//
if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
{
//
// if values are in ascending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
int h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
break;
//
// sort array values in ascending sort order
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
{
//
// if values are in descending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
int h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
break;
//
// if values are equal
// select next sort directive
//
}
}
}
//
// return sorted array
//
return array;
}
/// <summary>
/// Sorts two dimensional array type of double,
/// by selected culumns, in selected sort order.
/// Selection Sort Algorithm is implemented
/// for sorting values inside array.
/// </summary>
/// <param name="array">
/// Two dimensional array, type of double,
/// contaning values that are going to be sorted.
/// </param>
/// <param name="sort_directive">
/// Two dimensional array, type of int.
/// First column contains the order of the column indexes
/// by which the array will be sorted.
/// Second column contains column sort order.
/// Sort order for each column is defined by ineger values :
/// -1 - sort column values in Descending sort order
/// 0 - column is not going to be sorted
/// 1 - sort column values in Ascending sort order
/// </param>
/// <returns>
/// Sorted array by selected columns in selected sort order.
/// </returns>
public double[,] Sort_Double(double [,] array, int [,] sort_directive)
{
// number of rows iside array
int array_rows = array.GetLength(0);
// number of columns inside array
int array_columns = array.Length/array_rows;
// number of columns to be sorted
int sort_directive_columns = sort_directive.GetLength(0);
//
for(int i=0;i<array_rows-1;i++)
{
for(int j=i+1;j<array_rows;j++)
{
for(int c=0;c<sort_directive_columns;c++)
{
//
// sort array values in descending sort order
//
if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
{
//
// if values are in ascending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
double h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
break;
//
// sort array values in ascending sort order
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
{
//
// if values are in descending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
double h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
break;
//
// if values are equal
// select next sort directive
//
}
}
}
//
// return sorted array
//
return array;
}
/// <summary>
/// Sorts two dimensional array type of decimal,
/// by selected culumns, in selected sort order.
/// Selection Sort Algorithm is implemented
/// for sorting values inside array.
/// </summary>
/// <param name="array">
/// Two dimensional array, type of decimal,
/// contaning values that are going to be sorted.
/// </param>
/// <param name="sort_directive">
/// Two dimensional array, type of int.
/// First column contains the order of the column indexes
/// by which the array will be sorted.
/// Second column contains column sort order.
/// Sort order for each column is defined by ineger values :
/// -1 - sort column values in Descending sort order
/// 0 - column is not going to be sorted
/// 1 - sort column values in Ascending sort order
/// </param>
/// <returns>
/// Sorted array by selected columns in selected sort order.
/// </returns>
public decimal[,] Sort_Decimal(decimal [,] array, int [,] sort_directive)
{
// number of rows iside array
int array_rows = array.GetLength(0);
// number of columns inside array
int array_columns = array.Length/array_rows;
// number of columns to be sorted
int sort_directive_columns = sort_directive.GetLength(0);
//
for(int i=0;i<array_rows-1;i++)
{
for(int j=i+1;j<array_rows;j++)
{
for(int c=0;c<sort_directive_columns;c++)
{
//
// sort array values in descending sort order
//
if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
{
//
// if values are in ascending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
decimal h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
break;
//
// sort array values in ascending sort order
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
{
//
// if values are in descending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
decimal h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
break;
//
// if values are equal
// select next sort directive
//
}
}
}
//
// return sorted array
//
return array;
}
/// <summary>
/// Sorts two dimensional array type of float,
/// by selected culumns, in selected sort order.
/// Selection Sort Algorithm is implemented
/// for sorting values inside array.
/// </summary>
/// <param name="array">
/// Two dimensional array, type of float,
/// contaning values that are going to be sorted.
/// </param>
/// <param name="sort_directive">
/// Two dimensional array, type of int.
/// First column contains the order of the column indexes
/// by which the array will be sorted.
/// Second column contains column sort order.
/// Sort order for each column is defined by ineger values :
/// -1 - sort column values in Descending sort order
/// 0 - column is not going to be sorted
/// 1 - sort column values in Ascending sort order
/// </param>
/// <returns>
/// Sorted array by selected columns in selected sort order.
/// </returns>
public float[,] Sort_Float(float [,] array, int [,] sort_directive)
{
// number of rows iside array
int array_rows = array.GetLength(0);
// number of columns inside array
int array_columns = array.Length/array_rows;
// number of columns to be sorted
int sort_directive_columns = sort_directive.GetLength(0);
//
for(int i=0;i<array_rows-1;i++)
{
for(int j=i+1;j<array_rows;j++)
{
for(int c=0;c<sort_directive_columns;c++)
{
//
// sort array values in descending sort order
//
if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
{
//
// if values are in ascending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
float h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==-1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
break;
//
// sort array values in ascending sort order
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])>0)
{
//
// if values are in descending sort order
// swap values
//
for(int d=0;d<array_columns;d++)
{
float h = array[j,d];
array[j,d]=array[i,d];
array[i,d]=h;
}
break;
}
//
// if values are in correct sort order break
//
else if(sort_directive[c,1]==1 &&
array[i,sort_directive[c,0]].CompareTo(array[j,sort_directive[c,0]])<0)
break;
//
// if values are equal
// select next sort directive
//
}
}
}
//
// return sorted array
//
return array;
}
}


Amit MohantyPosted Jul 8, 2019, 11:19 PM
Nice......