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 by ThenBy()
for the second one:
private static uint NegativeToMaxValue(int i)
{
if (i < 0)
return uint.MaxValue;
return (uint)i;
}
…
var ordered = unorderered
.OrderBy(a => NegativeToMaxValue(Array.IndexOf(new[] { "y", "x" }, a)))
.ThenBy(a => a);
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 of IndexOf()
to uint
.)
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:
IComparer<string> comparer = KeyComparer<string>
.OrderBy(a => NegativeToMaxValue(Array.IndexOf(new[] { "y", "x" }, a)))
.ThenBy(a => a);