I have a requirement in my project, in which I need to sort the string which has alphanumeric data like below
CA101
CA20
CBC11
CMC12
So, I Would like to know how to sort alphanumeric kind of list easily and efficiently in C#, with or without using LINQ?
Here are the two ways to sort alphanumeric string in C#
First Method is using natural sort C# function
/// <summary>
/// Compares two sequences.
/// </summary>
/// <typeparam name="T">Type of item in the sequences.</typeparam>
/// <remarks>
/// Compares elements from the two input sequences in turn. If we
/// run out of list before finding unequal elements, then the shorter
/// list is deemed to be the lesser list.
/// </remarks>
public class EnumerableComparer<T> : IComparer<IEnumerable<T>>
{
/// <summary>
/// Create a sequence comparer using the default comparer for T.
/// </summary>
public EnumerableComparer()
{
comp = Comparer<T>.Default;
}
/// <summary>
/// Create a sequence comparer, using the specified item comparer
/// for T.
/// </summary>
/// <param name="comparer">Comparer for comparing each pair of
/// items from the sequences.</param>
public EnumerableComparer(IComparer<T> comparer)
{
comp = comparer;
}
/// <summary>
/// Object used for comparing each element.
/// </summary>
private IComparer<T> comp;
/// <summary>
/// Compare two sequences of T.
/// </summary>
/// <param name="x">First sequence.</param>
/// <param name="y">Second sequence.</param>
public int Compare(IEnumerable<T> x, IEnumerable<T> y)
{
using (IEnumerator<T> leftIt = x.GetEnumerator())
using (IEnumerator<T> rightIt = y.GetEnumerator())
{
while (true)
{
bool left = leftIt.MoveNext();
bool right = rightIt.MoveNext();
if (!(left || right)) return 0;
if (!left) return -1;
if (!right) return 1;
int itemResult = comp.Compare(leftIt.Current, rightIt.Current);
if (itemResult != 0) return itemResult;
}
}
}
}
Second Method is to pad the numeric portion & use OrderBy Clause
public static string PadNumbers(string input)
{
return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}
above functions pads zeros for any number (or numbers) that appear in the input string
Here is the complete C# console app with both functions implemented in it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace SortingAlphaNumericString
{
class Program
{
static void Main(string[] args)
{
string[] testItems = { "CA101", "CA102", "CA11", "z1",
"z3", "z20", "z5", "z11",
"z21", "z22" };
var SortedUsingPad = testItems.OrderBy(x => PadNumbers(x));
Console.WriteLine("Sorted data using PadNumbers");
foreach (var str in SortedUsingPad)
{
Console.WriteLine(str);
}
Func<string, object> convert = str =>
{
try { return int.Parse(str); }
catch { return str; }
};
Console.WriteLine();
var result = testItems.OrderBy(
str => Regex.Split(str.Replace(" ", ""), "([0-9]+)").Select(convert),
new EnumerableComparer<object>());
Console.WriteLine("Sorted list using Natural sort");
foreach(var str in result)
{
Console.WriteLine(str);
}
}
/// <summary>
/// Compares two sequences.
/// </summary>
/// <typeparam name="T">Type of item in the sequences.</typeparam>
/// <remarks>
/// Compares elements from the two input sequences in turn. If we
/// run out of list before finding unequal elements, then the shorter
/// list is deemed to be the lesser list.
/// </remarks>
public class EnumerableComparer<T> : IComparer<IEnumerable<T>>
{
/// <summary>
/// Create a sequence comparer using the default comparer for T.
/// </summary>
public EnumerableComparer()
{
comp = Comparer<T>.Default;
}
/// <summary>
/// Create a sequence comparer, using the specified item comparer
/// for T.
/// </summary>
/// <param name="comparer">Comparer for comparing each pair of
/// items from the sequences.</param>
public EnumerableComparer(IComparer<T> comparer)
{
comp = comparer;
}
/// <summary>
/// Object used for comparing each element.
/// </summary>
private IComparer<T> comp;
/// <summary>
/// Compare two sequences of T.
/// </summary>
/// <param name="x">First sequence.</param>
/// <param name="y">Second sequence.</param>
public int Compare(IEnumerable<T> x, IEnumerable<T> y)
{
using (IEnumerator<T> leftIt = x.GetEnumerator())
using (IEnumerator<T> rightIt = y.GetEnumerator())
{
while (true)
{
bool left = leftIt.MoveNext();
bool right = rightIt.MoveNext();
if (!(left || right)) return 0;
if (!left) return -1;
if (!right) return 1;
int itemResult = comp.Compare(leftIt.Current, rightIt.Current);
if (itemResult != 0) return itemResult;
}
}
}
}
public static string PadNumbers(string input)
{
return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}
}
}
Output
I will recommed to use natural sort method as, as pad numbers method will not when a string comes with space in between it like "z 12".
You can also simply use Lambda
var result = YourList.OrderBy(x => PadNumbers(x));
Where PadNumbers
public static string PadNumbers(string input)
{
return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}
Thanks
Subscribe to our weekly Newsletter & Keep getting latest article/questions in your inbox weekly