开发者

How to use C# delegate like functor in C++?

开发者 https://www.devze.com 2023-02-08 09:44 出处:网络
In C++, to sort a vector, a list or any collection, I would use: #include <iostream> #include <vector>

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;

in开发者_高级运维t 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


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.


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.


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.


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


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));


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. :-)

0

精彩评论

暂无评论...
验证码 换一张
取 消