0

Assume I have a collection of the form:

List<Member> myMembers= new List<Member>() 
{ 
    new Member(){ID=1,FirstName="John",LastName="Doe"}, 
    new Member(){ID=3,FirstName="Allan",LastName="Jones"}, 
    new Member(){ID=2,FirstName="Martin",LastName="Moe"}, 
    new Member(){ID=4,FirstName="Ludwig",LastName="Issac"} 
};

I can sort this list via FirstName by using:

myMembers.Sort((x, y) => x.FirstName.CompareTo(y.FirstName)); 

I would like to do this inside of a function, so that I can pass the desired search parameter. Something like:

public void sortCollection( parameter SearchTerm, List<Member> myCollection )
{
    myCollection ((x, y) => x.SearchTerm.CompareTo(y.FirstName)); 
}

Obviously here, I cannot pass in the desired search field this way, but is it possible to do what I am asking?

Selim Yildiz
  • 5,254
  • 6
  • 18
  • 28
pelt
  • 103
  • 1
  • 7
  • You can pass a function `Func` which will contain desired attribute – Fabio Feb 17 '20 at 06:32
  • I wouldn't bother with a method to do this. Just use `IEnumerable.OrderBy`, as it is, or `Sort`. and work on bigger fish – TheGeneral Feb 17 '20 at 06:33
  • Dont think you can deduce a property like that without reflection or some other sorcery. But a question, why are you using a sort predicate for basic built in types like String in this example? – Prateek Shrivastava Feb 17 '20 at 06:34
  • Please share an example of what you are trying to do. – Athanasios Kataras Feb 17 '20 at 06:35
  • Why do you want to make sorting as a function with generic search term. C# linq already gave us Linq `OrderBy()` and `Sort()` methods where you can pass predicate based on your requirement. Like `myMembers.Sort(x => x.Id);` or `myMembers.Sort(x => x.FirstName);` or `myMembers.Sort(x => x.LastName);` I believe you are just reinventing the wheels. Correct me if I am wrong here – Prasad Telkikar Feb 17 '20 at 06:38
  • Whats wrong with `myCollection.OrderBy(member => member.ID)`? Nice and simple. – RoadRunner Feb 17 '20 at 06:49
  • You can follow the `Dynamic Query Expressions` keyword. – Hamed Moghadasi Feb 17 '20 at 06:57
  • What would a `SearchTerm` be? Is it requested by user? If you want to define your own parameters, you may want to research about how to implement an `IComparer`. – Louis Go Feb 17 '20 at 06:59
  • The reason I want to do this, is so I don't have to retype the same line over and over. I created this example and is not my real use-case... my real data will have DOZENS of different columns of data in the collection. If I can create a function, I just past it the sort parameter, and the list, and it will save me from hard-coding in a bunch of different lines that will search on different parameters. – pelt Feb 17 '20 at 14:13

4 Answers4

1

You can create a generic extension method for that and pass Func<T, TResult> delegate to it, which is used as key selector for built-in Sort method

public static void SortExt<T, TValue>(this List<T> collection, Func<T, TValue> selector)
{
    var comparer = Comparer<TValue>.Default;
    collection.Sort((x, y) => comparer.Compare(selector(x), selector(y)));
}

Keep in mind that you should compare the same fields of compared objects.

Example of the usage

myMembers.SortExt(member => member.FirstName);

If you want to compare the myMembers collection only, the declaration can be simplified

public static void SortExt<TValue>(this List<Member> members, Func<Member, TValue> selector)
{
    var comparer = Comparer<TValue>.Default;
    members.Sort((x, y) => comparer.Compare(selector(x), selector(y)));
}

Another option is to introduce a Comparison<T> delegate instance to store the logic of field comparison and pass it to the Sort method. Here you can specify any custom comparison that you want

Comparison<Member> comparison = (x, y) => x.FirstName.CompareTo(y.FirstName);
myMembers.Sort(comparison);
Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66
0

Demo on dotnet fiddle

It seems to me that you can use Func<> to be able to dynamic order by.

var result = sortCollection(p => p.ID, myMembers);

public static IEnumerable<Member> sortCollection(Func<Member, object> keySelector, List<Member> myCollection)
{
    return myCollection.OrderBy(keySelector);
}

Read the following post to have a better understanding

Dynamic Order By in Linq

Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
  • 2
    This does nothing apart from creates more CIL and makes the user type more text to achieve the same thing – TheGeneral Feb 17 '20 at 06:47
0

Instead of writing one more wrapper on Linq .OrderBy() or .Sort() method and calling that where ever you want to sort, use Linq OrderBy() or .Sort() method

Use Sort() like

//If you want to sort collection by Id then
myMembers.Sort(x => x.Id); 

//If you want to sort collection by FirstName then
myMembers.Sort(x => x.FirstName);

...

To decide between OrderBy()/Sort() read below Q&A thread

C# Sort and OrderBy comparison

Prasad Telkikar
  • 15,207
  • 5
  • 21
  • 44
0

Why not simply use the built in function?

myMembers.OrderBy(m => m.FirstName)

If you really want to, you can write your own wrapper around this function, but the call would look more or less identical and would kind of be reinventing the wheel.

something like this extension method:

public static IEnumerable<T> OrderByWrapper<T, TKey>(this IEnumerable<T> source, Func<T,TKey> keySelector)
{
    return source.OrderBy(keySelector);
}

you would call it with:

myMembers.OrderByWrapper(m => m.FirstName)
Stefan
  • 652
  • 5
  • 10