4

In C++, to sort a vector, a list or any collection, I would use:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

int main() {
    vector<int> vt;
    vt.push_back( 3 );
    vt.push_back( 1 );
    vt.push_back( 2 );
    sort( vt.begin(), vt.end(), greater<int>() );
}

In C#, I found that List<> is equivalent to std::vector<>:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Professional_Csharp {
    class Program {
        static void Main( string[] args ) {
            List<int> intList = new List<int>();
            intList.Add( 3 );
            intList.Add( 2 );
            intList.Add( 1 );
            intList.Sort(); 
        }
    }
}

This worked fine, however if I want to customize the comparator, how could I implement that? Or if I want to sort just a specific range instead of the whole list? How could I do that?

Update

sort( vt.begin(), vt.begin() + 1 );

Is it possible in C#?

Thanks,
Chan

roxrook
  • 13,511
  • 40
  • 107
  • 156
  • I suggest you get rid of the C++ code in the question; the questions you asked at the end are specific enough. – Justin Feb 04 '11 at 19:32

6 Answers6

3

Throughout the .NET framework you will occasionaly find methods (like Sort) which have one or more overloads which accept additional types (either interfaces or delegates) to extend their behavior. Unlike C++, .NET does not have the same approach as the STL to composable algorithms.

In the case of List.Sort there are two overloads that you may find useful:

List.Sort( IComparer<T> comparer )    // and
List.Sort( Comparison<T> comparison ) // .NET 4.0 and up

The first overload accepts an instance of a type that implements IComparer<T> - an interface with a single method Compare. The second overload is only available if you're using .NET 4.0 or newer - it accepts a delegate (or lambda expression) which supplies the comparison semantics.

If you can, the second overload is much easier to use:

intList.Sort( (a,b) => YourCompare(a,b) /* your compare logic here */ );

To use the first overload, you must create a class or struct that implements IComparer<T>:

public sealed class YourComparer : IComparer<YourType>
{
    int Compare( YourType a, YourType b ) { ... }
}

intList.Sort( new YourComparer() );

If you don't want to alter the collection itself, but only sort it's items and operate on them as a new sequence you can use LINQ's OrderBy operator:

intList.OrderBy( x => ... ).ToArray() /* creates new sequence, won't alter intList */


To answer the second part of your question, if you want to sort just a specific range of a particular collection, you would have to use the Sort( int, int, IComparer<T> ) overload.
LBushkin
  • 129,300
  • 32
  • 216
  • 265
2

You can supply a comparison as a parameter to the sort method: http://msdn.microsoft.com/en-us/library/w56d4y5z.aspx. I would supply an example, but the one in that MSDN article should suffice.

Eric Mickelsen
  • 10,309
  • 2
  • 30
  • 41
2

List.Sort() has overloads which accept lambdas to perform comparisons. For instance:

public class ElementClass {public int A; public int B;}

...

List<ElementClass> myList = GetAListOfRandomElementClassInstances();

//sorts in ascending order by A, then B
myList.Sort((x,y)=> x.A > y.A 
                    ? 1 
                    : x.A < y.A 
                      ? -1 
                      : x.B > y.B 
                        ? 1 
                        : x.B < y.B 
                          ? -1 
                          : 0);

List.Sort() will also take an IComparer, allowing you to encapsulate custom sorting behavior:

public class ElementClassComparer : IComparer<int>
{
    public int Compare(int a, int b)
    {
        return x.A > y.A ? 1 : x.A < y.A ? -1 : x.B > y.B ? 1 : x.B < y.B ? -1 : 0
    }
}

...

myList.Sort(new ElementClassComparer());

The Linq library also has an OrderBy() method that will sort by any IComparable projection:

myList = myList.OrderBy(x=>x.A).ThenBy(x=>x.B).ToList();

This is a less efficient but much more readable version of the above sorts.

KeithS
  • 70,210
  • 21
  • 112
  • 164
1

You can use List<T>.Sort(IComparer<T>) and write your custom IComparer. Documentation

Christoph
  • 4,251
  • 3
  • 24
  • 38
1

As has been mentioned, List.Sort has a few useful overloads. Here are just some implementation examples.

IComparer<T>

public class MyComparer : IComparer<int> {
    public int Compare(int x, int y) {
        return x - y;
    }
}

...

List<int> list = new List<int>();

// Example start/end indexes
int startIndex = 0, endIndex = list.Count;

// Use IComparer<T>
MyComparer comparer = new MyComparer();
list.Sort(startIndex, endIndex, comparer);

Comparison<T>

static int MyCompareMethod(int x, int y) {
    return x - y;
}

...

// Use Comparison<T>
list.Sort((x, y) => MyCompareMethod(x, y));
bitxwise
  • 3,534
  • 2
  • 17
  • 22
1

Although my post doesn't attempt to answer your question, as people already have given that. So I would talk about an alternative.

Suppose you want to sort Person by Age, then you can write query like code:

var sortedPersons = from person in persons
                    where true
                    orderby person.Age ascending
                    select person;

This syntax is very expressive and so appealing that recently I had started the following topic on it.

Which is fast : Query Syntax vs. Loops

Check it out. :-)

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851