Ive just written the following code, which will order strings by their native string.Compare() but allow a collection of exceptions (in this case customPriority) that will place priority over the default string.Compare() function.
It all seems a bit long winded, I was wondering if there was something built into .NET to allow this?
var unorderered = new[] { "a", "b", "c", "x", "y", "z" };
var ordered = unorderered.OrderBy(a => a, new CustomStringComparer());
//expected order y,x,a,b,c,z
class CustomStringComparer : IComparer<string>
{
int IComparer<string>.Compare(string x, string y)
{
if (x == y)
return 0;
else
{
//----------------------------
//beginning of custom ordering
var customPriority = new[] { "y", "x" };
if (customPriority.Any(a => a == x) && customPriority.Any(a => a == y)) //both in custom ordered array
{
if (Array.IndexOf(customPriority, x) < Array.IndexOf(customPriority, y))
return -1;
return 1;
}
else if (customPriority.Any(a => a == x)) //only one item in custom ordered array (and its x)
return -1;
else if (customPriority.Any(a => a == y)) //only one item in custom ordered array (and its y)
return 1;
//---------------------------
//degrade to default ordering
else
return string.Compare(x, y);
}
}
}
First, I think it’s useful to restate the problem: You want to sort by:
That means you can achieve your sort order by using
OrderBy()for the first condition followed byThenBy()for the second one:NegativeToMaxValue()is necessary, because items not in the array should be last, but they would be first normally, because the index is -1. (A hackish and unreadable way to do the same would be to directly cast the result ofIndexOf()touint.)If you wanted to reuse this sorting by creating an
IComparer, I believe there is nothing in .Net to help you with that. But you could use ComparerExtensions instead: