开发者

How to sort a list using my own logic (not alphabetically or numerically)

开发者 https://www.devze.com 2023-04-06 23:47 出处:网络
I\'ve spent the last 30 mins looking through existing answers for what I think is a common question, but nothing quite hits it for me. Apologies if this is a dupe.

I've spent the last 30 mins looking through existing answers for what I think is a common question, but nothing quite hits it for me. Apologies if this is a dupe.

I've got a list of objects.

List<Journey> journeys;

The object has a 'status' property - this is a string.

class Journey
{
    public string Name;
    public string Status; 
}

I want to sort based on this string, however not alphabetically. The status depicts the object's position through a journey, either "Enroute", "Finished", or "Error". When sorted ascending I want them to appear in the following order: "Error", "Enroute", "Finished". (In practice there are more statuses than this so renaming them to fall in alphabetical order isn't an option)

Aside from creating a class for 'status' with va开发者_开发百科lue and sort order properties, and then sorting based on that, how do I do this? Or is that the best method?


You can define the you sorting logic inside of custom function which is provided to Comparison delegate:

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

list.Sort(new Comparison<Journey>((Journey source, Journey compare) => 
{ 
    // here is my custom compare logic
    return // -1, 0 or 1
}));


Just another thought:

class Journey
{
    public enum JourneyStatus
    {
        Enroute,
        Finished,
        Error
    }

    public string Name;
    public JourneyStatus Status;
}

Used with OrderBy:

var journeys = new List<Journey>();
journeys.Add(new Journey() { Name = "Test1", Status = Journey.JourneyStatus.Enroute });
journeys.Add(new Journey() { Name = "Test2", Status = Journey.JourneyStatus.Error });
journeys.Add(new Journey() { Name = "Test3", Status = Journey.JourneyStatus.Finished });
journeys.Add(new Journey() { Name = "Test4", Status = Journey.JourneyStatus.Enroute });

journeys = journeys.OrderBy(x => x.Status).ToList();

foreach (var j in journeys)
    Console.WriteLine("{0} : {1}", j.Name, j.Status);

Output:

Test1 : Enroute
Test4 : Enroute
Test3 : Finished
Test2 : Error

Or you might modify the lambda passed to OrderBy to map the value of Status string to an int.

In some situations you might want to implement IComparer<T>, like Jon said. It can help keeping the sorting logic and the class definition itself in one place.


You need to create a class that implements IComparer<Journey> and implement the Compare method accordingly.

You don't mention how you are sorting exactly, but pretty much all methods of the BCL that involve sorting have an overload that accepts an IComparer so that you can plug in your logic.


Aside from creating a class for 'status' with value and sort order properties, and then sorting based on that, how do I do this?

As this is some custom order you need creating such a class is a good idea.


Derive from Comparer<T> or StringComparer class, implement class with your custom logic, pass instance of this class to sort method.


One way to do this is to assign an order number to each item. So create a database table to hold your items and their order:

Column Name, Column Order
Enrout , 0
Finished, 1
Error, 2

Then when I populate a drop down I can sort by the Order in my SQL select rather than the name.

Or if you don't want to use a database, you could change Status to include the order and then just parse out the Status name: so Status values might look like this: "0,Enrout","1,Finished","2,Error" then it will naturally sort. Then just use split to separate the order from the name:

string[] statusArr = status.split(',');
string order = statusArr[0];
string statusname = statusArr[1];

There's a lot of ways to skin this cat.

0

精彩评论

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

关注公众号