Reputation: 23841
I have the following collection:
-3, -2, -1, 0, 1, 2, 3
How can I in a single order by
statement sort them in the following form:
The negative numbers are sorted first by their (absolute value) then the positive numbers.
-1, -2, -3, 0, 1, 2, 3
Upvotes: 2
Views: 2411
Reputation: 14605
Combination sorting, first by the sign, then by the absolute value:
list.OrderBy(x => Math.Sign(x)).ThenBy(x => Math.Abs(x));
or:
from x in list
orderby Math.Sign(x), Math.Abs(x)
select x;
This is conceptually similar to the SQL statement:
SELECT x
FROM list
ORDER BY SIGN(x), ABS(x)
In LINQ-to-Objects, the sort is performed only once, not twice.
WARNING: Math.Abs(x) will fail if x == int.MinValue. If this marginal case is important, then you have to handle it separately.
Upvotes: 7
Reputation: 17782
var numbers = new[] { -3, -2, -1, 0, 1, 2, 3 };
var customSorted = numbers.OrderBy(n => n < 0 ? int.MinValue - n : n);
The idea here is to compare non-negative numbers by the value they have. And compare negative numbers with the value int.MinValue - n
which is -2147483648 - n
and because n
is negative, the higher negative number we, the lower negative result the outcome will be.
It doesn't work when the list itself contains the number int.MinValue
because this evaluates to 0
which would be equal to 0
itself. As Richard propose it could be made with long
´s if you need the full range but the performance will be slightly impaired by this.
Upvotes: 6
Reputation: 16864
You could express it in LINQ, but if I were reading the code two years later, I'd prefer to see something like:
list.OrderBy(i=>i, new NegativeThenPositiveByAscendingAbsoluteValueComparer());
You will need to implement IComparer.
Upvotes: 0
Reputation: 2251
Try something like (VB.Net example)
Orderby(Function(x) iif(x<0, Math.Abs(x), x*1000))
...if the values are <1000
Upvotes: 1