Reputation: 1529
I have a collection of integers e.g.
INPUT EXAMPLE
4,7,9,8,20,56,78,34,2,76,84,98
I need to sort this list in a way that any number til 20 will be sorted in ascending order and above 20 will be sorted in descending order. So output will be :
OUTPUT EXAMPLE
2,4,7,8,9,20,98,84,78,76,56,34
I wrote a comparer for it. but now trying for more clean approach may be by using the existing tools like orderby.
Upvotes: 0
Views: 4118
Reputation: 22886
int[] a = { 4, 7, 9, 8, 20, 56, 78, 34, 2, 76, 84, 98 };
var b = a.OrderBy(i => i > 20 ? int.MaxValue - i : i);
If possible, I recommend sorting in-place. For example ( can be improved )
Array.Sort(a, (i1, i2) => (i1 > 20 ? int.MaxValue - i1 : i1) - (i2 > 20 ? int.MaxValue - i2 : i2));
Upvotes: 0
Reputation: 152624
You can do that using two sort groups:
list.OrderBy(i => i <= 20 ? i : int.MaxValue) // sort numbers less than 20 ascending; put numbers greater than 20 at the end
.ThenByDescending(i => i) // sort remaining numbers descending
Upvotes: 7
Reputation: 1871
[Test]
public void SortTill20AscRestDesc()
{
var src = new[] {4, 7, 9, 8, 20, 56, 78, 34, 2, 76, 84, 98};
var expected = new[] {2, 4, 7, 8, 9, 20, 98, 84, 78, 76, 56, 34};
var result = src
.Select(
i => new
{
IsAbove20 = i > 20,
Value = i
}
)
.OrderBy(e => e.IsAbove20)
.ThenBy(e => e.IsAbove20 ? int.MaxValue : e.Value)
.ThenByDescending(e => e.Value)
.Select(e=>e.Value);
Assert.That(result.SequenceEqual(expected), Is.True);
}
Upvotes: -1
Reputation: 151720
You can trivially do this using a custom comparer:
public class MyCustomComparer : IComparer<int>
{
private readonly int _cutOffPointInclusive;
public MyCustomComparer(int cutOffPointInclusive)
{
_cutOffPointInclusive = cutOffPointInclusive;
}
public int Compare(int x, int y)
{
if (x <= _cutOffPointInclusive || y <= _cutOffPointInclusive)
{
return x.CompareTo(y);
}
else
{
return y.CompareTo(x);
}
}
}
This sorts ascendingly when either value to compare is lower than or equal to the cutoff point (both to push the greater values to the top and to sort the values up till the cutoff point ascendingly), and descendingly when both are greater than the cutoff point (to actually sort those greater values descendingly).
Tested using:
var testData = new List<int>{ 4,7,9,8,20,56,78,34,2,76,84,98 };
testData.Sort(new MyCustomComparer(20));
foreach (var i in testData)
{
Console.WriteLine(i);
}
Output:
2
4
7
8
9
20
98
84
78
76
56
34
See also http://ideone.com/YlVH8i. So I don't really think this isn't "clean", but just fine.
Upvotes: 4
Reputation: 5890
Why don't use two steps?
var bellow = originallist.Where(i => i <= 20).OrderBy(i);
var above= originallist.Where(i => i > 20).OrderByDescending(i);
var sorted = bellow.Concat(above).ToList();
Upvotes: 1