Reputation: 6668
I want to sort a custom list I have on a certain criteria. Every item in my list contains a property called "Status" which is a enumeration, shown below.
Empty = 0, Normal = 1, Aged = 2, Dead = 3
The values assigned above cannot be changed. When I sort on my Status property I would like the order to be as such Normal, Aged, Empty & Dead. I do not know how best to go about this?
Below is an example of a class I'm using for a different sorting issue. Not sure how I would 'convert' this class to solve my issue above?
public class SortOrders : IComparer<OrderBlocks.Order>
{
private bool _sortDescending;
public SortOrders(bool sortDescending)
{
this._sortDescending = sortDescending;
}
public SortOrders()
: this(false) // sort ascending by default
{
}
public int Compare(OrderBlocks.Order x, OrderBlocks.Order y)
{
if (this._sortDescending)
{
return y.StatusGood.CompareTo(x.StatusGood);
}
else
{
return x.StatusGood.CompareTo(y.StatusGood);
}
}
}
Upvotes: 2
Views: 214
Reputation: 786
I would create a conversion function that StatusGood is passed through prior to comparing it, ie:
public static class StatusGoodExtensions
{
public static int OrderIndex(this StatusGood statusIn)
{
switch ( statusIn )
{
case StatusGood.Normal: return 0;
case StatusGood.Aged: return 1;
case StatusGood.Empty: return 2;
case StatusGood.Dead: return 3;
}
throw new NotImplementedException(statusIn.ToString());
}
}
using in the comparison, like so:
return x.StatusGood.OrderIndex().CompareTo(y.StatusGood.OrderIndex());
By having an extension method, the logic to return the order is cleanly separated from the sorting, and could be tested or re-used elsewhere.
Upvotes: 1
Reputation: 17048
The order by linq extension take a Func<TSource, TKey> keySelector
, so you can pass a custom ordered method that return an int value base on the order you need:
public enum Status { Empty = 0, Normal = 1, Aged = 2, Dead = 3 }
public class Item
{
public Status Status { get; set; }
public int OrderedStatus
{
get
{
switch (this.Status)
{
case Status.Normal: return 0;
case Status.Aged: return 1;
case Status.Empty: return 2;
default: return 3; // case Status.Dead
}
}
}
public static IEnumerable<Item> OrderByStatus(IEnumerable<Item> items)
{
return items.OrderBy(item => item.OrderedStatus);
}
}
Upvotes: 1
Reputation: 14608
There are lots ways to do it using OrderBy:
Chaining OrderBy
and ThenBy
calls together with your custom order:
var ordered = list.OrderBy(f1 => f1.Status == 3)
.ThenBy(f2 => f2.Status == 0)
.ThenBy(f3 => f3.Status == 2)
.ThenBy(f4 => f4.Status == 1).ToList();
Or use a delegate switch/case inline:
var ordered2 = list.OrderBy(foo =>
{
switch (foo.Status)
{
case (int)Status.Normal:
return 0;
case (int)Status.Aged:
return 1;
case (int)Status.Empty:
return 2;
case (int)Status.Dead:
return 3;
default:
return 0;
}
}).ToList();
Both give the same results. The first method uses the enum values you already have, the second looks at the enum value and returns a different integer to be used for comparison.
Upvotes: 0
Reputation: 6733
Here's how I would do it using Linq:
var sorted = myList.OrderBy(x =>
{
switch (x.Status)
{
case SomethingStatus.Normal:
return 0;
case SomethingStatus.Aged:
return 1;
case SomethingStatus.Empty:
return 2;
case SomethingStatus.Dead:
return 3;
default:
return 10;
}
});
Upvotes: 2