Is there a way in Linq to do an OrderBy against a set of values (strings in this case) without knowing the order of the values?
Consider this data:
A
B
A
C
B
C
D
E
And these variables:
string firstPref, secondPref, thirdPref;
When the values are set like so:
firstPref = 'A';
secondPref = 'B';
thirdPref = 'C';
Is it possible to order the data like so:
A
A
B
B
C
C
D
E
Danbrucs solution is more elegant, but here is a solution using a custom IComparer. This might be useful if you need more advanced conditions for your sort ordering.
Not really efficient for large lists but fairly easy to read:
Usage:
Note:
Array.IndexOf<T>(....)
usesEqualityComparer<T>.Default
to find the target index.Put the preferred values in a dictionary. Looking up keys in a dictionary is a O(1) operation compared to finding values in a list which is a O(n) operation, so it scales much better.
Create a sort string for each preferred value so that they are placed before the other values. For the other values the value itself will be used as sorting string so that they are actually sorted. (Using any arbitrary high value would only place them at the end of the list unsorted).
If you put your preferences into a list, it might become easier.
This will put all items not appearing in
preferences
in front becauseIndexOf()
returns-1
. An ad hoc work around might be reversingpreferences
and order the result descending. This becomes quite ugly, but works.The solution becomes a bit nicer if you concat
preferences
anddata
.I don't like
Concat()
andToList()
in there. But for the moment I have no really good way around that. I am looking for a nice trick to turn the-1
of the first example into a big number.In addition to @Daniel Brückner answer and problem defined at the end of it:
I think that the solution is to use a statement lambda instead of an expression lambda.
The ordered data is:
Combined all answers (and more) into a generic LINQ extension supporting caching which handles any data type, can be case-insensitive and allows to be chained with pre- and post-ordering:
Sample usage using LINQPad-Dump():