Ashish Rajput
Ashish Rajput

Reputation: 1529

Sorting a list in ascending and descending order

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

Answers (5)

Slai
Slai

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

D Stanley
D Stanley

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

Vitaliy Kalinin
Vitaliy Kalinin

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

CodeCaster
CodeCaster

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

Marko Juvančič
Marko Juvančič

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

Related Questions