While I am having difficulty finding any documentation to this effect, it appears as though the DataTable
class itself is order agnostic - that is to say, it will present the records in the sequence in which they were loaded (in the case of a DataTable
loaded through an adapter, this would be the order of the rows in the result set).
It is possible to extract the records in a specific sort order (as seen here: Sorting rows in a data table) and create a new DataTable
with the rows in this new sequence. This seems to be how most people gain the effect of a sort.
However the Select
method accepts its sorting condition as a string (http://msdn.microsoft.com/en-us/library/way3dy9w(v=vs.110).aspx) which means that the sort conditions are limited to those supported by the class. All the documentation indicates to be supported is a column name and a direction.
Since what you want is a custom sortation, not a basic one by column, it would appear that the base DataTable
has no mechanism for handling this built-in. What I would expect to be necessary in your scenario is to write some code to extract the records from the DataTable
, sort them with a custom sorter (using LINQ's OrderBy
with a function on the extracted data would probably do the trick), and then insert them into a new DataTable
that your code uses going forward.
As an example of this approach:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
DataTable inputDataTable = CreateInputDataTable();
Console.WriteLine("Input data table: ");
PrintDataTable(inputDataTable);
DataTable outputDataTable = CustomSortDataTable(inputDataTable);
Console.WriteLine("Sorted data table: ");
PrintDataTable(outputDataTable);
}
private static DataTable CustomSortDataTable(DataTable inputDataTable)
{
DataRow[] rows = inputDataTable.Select();
IComparer<string> animalTypeComparer = new AnimalTypeComparer();
IEnumerable<DataRow> sortedRows = rows.OrderBy(x => x["AnimalType"].ToString(), animalTypeComparer);
DataTable result = new DataTable();
result.Columns.Add("ID");
result.Columns.Add("AnimalType");
foreach(DataRow row in sortedRows)
{
result.ImportRow(row);
}
return result;
}
private static void PrintDataTable(DataTable inputDataTable)
{
foreach(DataRow row in inputDataTable.Rows)
{
Console.WriteLine("({0}, {1})", row["ID"], row["AnimalType"]);
}
}
private static DataTable CreateInputDataTable()
{
DataTable result = new DataTable();
result.Columns.Add("ID");
result.Columns.Add("AnimalType");
DataRow toInsert = result.NewRow();
toInsert["ID"] = 1;
toInsert["AnimalType"] = "Cat";
result.Rows.Add(toInsert);
toInsert = result.NewRow();
toInsert["ID"] = 2;
toInsert["AnimalType"] = "Cat";
result.Rows.Add(toInsert);
toInsert = result.NewRow();
toInsert["ID"] = 3;
toInsert["AnimalType"] = "Bird";
result.Rows.Add(toInsert);
toInsert = result.NewRow();
toInsert["ID"] = 4;
toInsert["AnimalType"] = "Bird";
result.Rows.Add(toInsert);
toInsert = result.NewRow();
toInsert["ID"] = 5;
toInsert["AnimalType"] = "Dog";
result.Rows.Add(toInsert);
toInsert = result.NewRow();
toInsert["ID"] = 6;
toInsert["AnimalType"] = "Dog";
result.Rows.Add(toInsert);
toInsert = result.NewRow();
toInsert["ID"] = 7;
toInsert["AnimalType"] = "Hamster";
result.Rows.Add(toInsert);
toInsert = result.NewRow();
toInsert["ID"] = 8;
toInsert["AnimalType"] = "Hamster";
result.Rows.Add(toInsert);
return result;
}
}
class AnimalTypeComparer : IComparer<string>
{
private static readonly string[] AnimalTypes = {"Hamster", "Bird", "Cat", "Dog"};
#region Implementation of IComparer<in string>
/// <summary>
/// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
/// </summary>
/// <returns>
/// A signed integer that indicates the relative values of <paramref name="x"/> and <paramref name="y"/>, as shown in the following table.Value Meaning Less than zero<paramref name="x"/> is less than <paramref name="y"/>.Zero<paramref name="x"/> equals <paramref name="y"/>.Greater than zero<paramref name="x"/> is greater than <paramref name="y"/>.
/// </returns>
/// <param name="x">The first object to compare.</param><param name="y">The second object to compare.</param>
public int Compare(string x, string y)
{
return Array.IndexOf(AnimalTypes, x).CompareTo(Array.IndexOf(AnimalTypes, y));
}
#endregion
}
}
Running this prints out the following:
Input data table:
(1, Cat)
(2, Cat)
(3, Bird)
(4, Bird)
(5, Dog)
(6, Dog)
(7, Hamster)
(8, Hamster)
Sorted data table:
(7, Hamster)
(8, Hamster)
(3, Bird)
(4, Bird)
(1, Cat)
(2, Cat)
(5, Dog)
(6, Dog)