Anton
Anton

Reputation: 1030

Wrong List.Sort() behaviour

I've got a List of Position objects that I retrive from EF DB context

+--------+---------------------+-------+-------+
|   ID   |      FullDate       | Year  | Month |
+--------+---------------------+-------+-------+
| 21952  | null                | 2015  | 1     |
| 21953  | null                | 2015  | 1     |
| 21954  | null                | 2015  | 1     |
| 21955  | null                | 2015  | 2     |
| 21956  | null                | 2015  | 1     |
| 21957  | null                | 2015  | 2     |
| 21958  | null                | 2015  | 3     |
| 21959  | null                | 2015  | 1     |
| 21960  | null                | 2015  | 1     |
| 21961  | null                | 2015  | 1     |
| 21962  | null                | 2015  | 2     |
| 21963  | null                | 2015  | 2     |
| 21964  | null                | 2015  | 2     |
| 21965  | null                | 2015  | 2     |
| 21966  | 01.02.2015 0:00:00  | null  | null  |
| 21967  | null                | 2015  | 2     |
| 21968  | null                | 2015  | 2     |
| 21969  | null                | 2015  | 2     |
| 21970  | null                | 2015  | 2     |
| 21971  | null                | 2015  | 3     |
| 21972  | null                | 2015  | 3     |
| 21973  | null                | 2015  | 3     |
| 21974  | null                | 2015  | 3     |
| 21975  | null                | 2015  | 3     |
| 21976  | null                | 2015  | 4     |
| 21977  | null                | 2015  | 4     |
| 21978  | null                | 2015  | 4     |
| 21979  | null                | 2015  | 4     |
| 21980  | null                | 2015  | 4     |
| 21981  | null                | 2015  | 5     |
| 21982  | null                | 2015  | 5     |
| 21984  | null                | 2015  | 6     |
| 21983  | null                | 2015  | 5     |
+--------+---------------------+-------+-------+

I've impemented a sorting like so:

positions.Sort((x, y) =>
{
    var xDate = getActualDate(x.FullDate, x.Year, x.Month);
    var yDate = getActualDate(y.FullDate, y.Year, y.Month);
    if (xDate > yDate)
    {
        return 1;
    }
    if (xDate == yDate && x.Id> y.Id)
    {
        return 1;                                              
    }                                    
    return -1;
});

Method for getting actual date is

private DateTime getActualDate(DateTime? fullDate, int? year, int? month)
{
    return fullDate.HasValue ? fullDate.Value : new DateTime(year.Value, month.Value, DateTime.DaysInMonth(year.Value, month.Value));
}

Every time i try to sort last rows are not changing even if in comparator expression return 1 nothing is changed. I've tried to debug Comparator method but get no results everything seems to work without erros exept the result of a sort :(

Upvotes: 0

Views: 487

Answers (2)

D Stanley
D Stanley

Reputation: 152616

They can't be actually equal because they'll have different Id's and comparator method will compare Id's in case of equal dates

You still need to code an "equals" case because List.Sort will compare an item to itself at certain points in the process. Comparing an item to itself should always return 0.

Luckily, the case is easy enough to inject:

positions.Sort((x, y) =>
{
    var xDate = getActualDate(x.FullDate, x.Year, x.Month);
    var yDate = getActualDate(y.FullDate, y.Year, y.Month);
    if (xDate == yDate && x.Id == y.Id)
    {
        return 0;                                              
    }                                    
    if (xDate > yDate)
    {
        return 1;
    }
    if (xDate == yDate && x.Id> y.Id)
    {
        return 1;                                              
    }                                    
    return -1;
});

You can rearrange or logically reduce the comparisons, if you like, but the logic should be the same.

Upvotes: 2

Robert McKee
Robert McKee

Reputation: 21477

Not sure why the sort isn't working, but this should:

var result=positions.Select(p=> new { 
  id, 
  date = p.fullDate ?? new DateTime(p.year.Value, p.month.Value, DateTime.DaysInMonth(p.year.Value, p.month.Value))
}).OrderBy(p=>p.date)
  .ThenBy(p=>p.id);

Upvotes: 1

Related Questions