earthling
earthling

Reputation: 5264

Custom Sorting of List<T>

I have a List<T> where T is my Event type which has a field time of type long. This list is populated from a web service and if an event doesn't have a time, the value set is 0.

What i want to do is sort my list ascending by time, but place the items with time=0 at the very bottom.

Currently I am accomplishing this in a hack sort of fashion and I want to learn a better way.

var events = new ObservableCollection<Event>();
var resp = JsonConvert.DeserializeObject<Events>(restResponse.Content).Items;

var notime = resp.Where(r => r.time == 0);
var yestime = resp.Where(r => r.time > 0);

yestime.ToList().ForEach(events.Add);
notime.ToList().ForEach(events.Add);

CallbackInternal(callback, events);

I attempted implementing a custom IComparer, but that didn't work out so well (here is one shot at it)

public class EventComparer : IComparer<Event>
{
    public int Compare(Event x, Event y)
    {
        if (x.time == 0) return 0;
        if (x.time < y.time) return -1;
        if (x.time > y.time) return 1;
        return 0;
    }
}

guidance is appreciated!

thanks!

Upvotes: 3

Views: 443

Answers (5)

Spook
Spook

Reputation: 25927

Try this one (you have to adjust it for your needs):

    class Comparer : IComparer<int>
    {
        public int Compare(int x, int y)
        {
            if (x == y) return 0;
            else if (x == 0) return 1;
            else if (y == 0) return -1;
            else if (x < y) return -1;
            else if (x > y) return 1;
        }
    }

Upvotes: 1

Phil
Phil

Reputation: 42991

Try

   events.OrderBy (e => e.Time == 0).ThenBy (e => e.Time);

Upvotes: 11

phoog
phoog

Reputation: 43046

Your custom IComparer is incorrect. With correct logic, it should work just fine. The problem is that if the left value is zero, any value will be equal to it. This means that 0 == 3 is true, and 3 > 0 is true. In fact, 0 > 3 and 3 < 0 should be true

You should do something like this instead:

if (x.time == y.time) return 0;
if (x.time == 0) return 1;
if (y.time == 0) return -1;
return x.time.CompareTo(y.time);

Upvotes: 1

Jeff
Jeff

Reputation: 36573

You could use LINQ:

resp.OrderBy(i => i.time == 0 ? int.MaxValue : i.time);

Upvotes: 2

zmbq
zmbq

Reputation: 39013

You should do something like this:

 if(x.time==y.time) return 0;
 if(x.time==0) return 1;
 return x.time - y.time;

The point here is that 0 is larger than any other time, so it'll be placed at the end of the list.

Upvotes: 1

Related Questions