Currently, i'm sorting a list using LINQ to objects, then doing a ToList()
on the results:
var SortedPossibleMoveLocations = (from PML in PossibleMoveLocations
orderby Randomiser.Next()
orderby IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0
orderby PossibleMoveLocationOrdering(PML)
select PML).ToList();
I want to convert this to do an inplace sort, i guess using List<T>.Sort()
method. If i was only ordering by one thing i'd know how to do this, however, as i'm ordering by PossibleMoveLocationOrdering
(which returns an int
) then by IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0
which evaluates to an int
, then by Randomiser.Next()
(which returns a random int) i don't know how to do this.
Question: How do i write the comparison function (or is there a better method) to do an implace sort of the LINQ query above.
To start with, specifying three orderby
clauses is a bad idea - instead, specify multiple orderings just by using comma separation.
I'm also not keen on the idea of using Randomiser.Next()
for ordering, but that's an aside.
Your LINQ query should look like this (still with Randomiser
in for the moment):
var query = (from PML in PossibleMoveLocations
orderby PossibleMoveLocationOrdering(PML),
IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0,
Randomiser.Next()
select PML).ToList();
Personally I'd just use dot notation for this:
var query = PossibleMoveLocations
.OrderBy(pml => PossibleMoveLocationOrdering(PML))
.ThenBy(pml => IsSameType(pml) ?
(_Owner[pml] as TileFlowing).UnitsWithin : 0)
.ThenBy(pml => Randomiser.Next())
.ToList();
To sort in place, you basically need a Comparison<T>
or IComparer<T>
which can test multiple things, and also an implementation which creates a comparer using properties. You can do that manually (as per Marc's code), but as it happens, I have some helper classes and extension methods in MiscUtil:
var comparer = ProjectionComparer<PossibleMove>
.Create(pml => PossibleMoveLocationOrdering(PML));
.ThenBy(pml => IsSameType(pml) ? ...)
.ThenBy(...);
list.Sort(comparer);
Note that using a Randomizer
here is definitely a bad idea, as it will be called on each comparison (for objects with equal first parts)... this can lead to an inconsistent comparison such that x
< y
< z
< x
.
Most commonly:
list.Sort((x,y) => {
int result = /* first comparison, for example
string.Compare(x.Name, y.Name) */
if (result == 0) result = /* second comparison,
for example x.Id.CompareTo(y.Id) */
...
if (result == 0) result = /* final comparison */
return result;
});
or similar (perhaps in a comparer class, if it is non-trivial).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With