I have a class called Order
which has properties such as OrderId
, OrderDate
, Quantity
, and Total
. I have a l
To do this without LINQ on .Net2.0:
List<Order> objListOrder = GetOrderList();
objListOrder.Sort(
delegate(Order p1, Order p2)
{
return p1.OrderDate.CompareTo(p2.OrderDate);
}
);
If you're on .Net3.0, then LukeH's answer is what you're after.
To sort on multiple properties, you can still do it within a delegate. For example:
orderList.Sort(
delegate(Order p1, Order p2)
{
int compareDate = p1.Date.CompareTo(p2.Date);
if (compareDate == 0)
{
return p2.OrderID.CompareTo(p1.OrderID);
}
return compareDate;
}
);
This would give you ascending dates with descending orderIds.
However, I wouldn't recommend sticking delegates as it will mean lots of places without code re-use. You should implement an IComparer
and just pass that through to your Sort
method. See here.
public class MyOrderingClass : IComparer<Order>
{
public int Compare(Order x, Order y)
{
int compareDate = x.Date.CompareTo(y.Date);
if (compareDate == 0)
{
return x.OrderID.CompareTo(y.OrderID);
}
return compareDate;
}
}
And then to use this IComparer class, just instantiate it and pass it to your Sort method:
IComparer<Order> comparer = new MyOrderingClass();
orderList.Sort(comparer);
Here is a generic LINQ extension method that does not create an extra copy of the list:
public static void Sort<T,U>(this List<T> list, Func<T, U> expression)
where U : IComparable<U>
{
list.Sort((x, y) => expression.Invoke(x).CompareTo(expression.Invoke(y)));
}
To use it:
myList.Sort(x=> x.myProperty);
I recently built this additional one which accepts an ICompare<U>
, so that you can customize the comparison. This came in handy when I needed to do a Natural string sort:
public static void Sort<T, U>(this List<T> list, Func<T, U> expression, IComparer<U> comparer)
where U : IComparable<U>
{
list.Sort((x, y) => comparer.Compare(expression.Invoke(x), expression.Invoke(y)));
}
Anybody working with nullable types, Value
is required to use CompareTo
.
objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));
Doing it without Linq as you said:
public class Order : IComparable
{
public DateTime OrderDate { get; set; }
public int OrderId { get; set; }
public int CompareTo(object obj)
{
Order orderToCompare = obj as Order;
if (orderToCompare.OrderDate < OrderDate || orderToCompare.OrderId < OrderId)
{
return 1;
}
if (orderToCompare.OrderDate > OrderDate || orderToCompare.OrderId > OrderId)
{
return -1;
}
// The orders are equivalent.
return 0;
}
}
Then just call .sort() on your list of Orders
You can do something more generic about the properties selection yet be specific about the type you're selecting from, in your case 'Order':
write your function as a generic one:
public List<Order> GetOrderList<T>(IEnumerable<Order> orders, Func<Order, T> propertySelector)
{
return (from order in orders
orderby propertySelector(order)
select order).ToList();
}
and then use it like this:
var ordersOrderedByDate = GetOrderList(orders, x => x.OrderDate);
You can be even more generic and define an open type for what you want to order:
public List<T> OrderBy<T,P>(IEnumerable<T> collection, Func<T,P> propertySelector)
{
return (from item in collection
orderby propertySelector(item)
select item).ToList();
}
and use it the same way:
var ordersOrderedByDate = OrderBy(orders, x => x.OrderDate);
Which is a stupid unnecessary complex way of doing a LINQ style 'OrderBy', But it may give you a clue of how it can be implemented in a generic way
Suppose you have the following code, in this code, we have a Passenger class with a couple of properties that we want to sort based on.
public class Passenger
{
public string Name { get; }
public string LastName { get; }
public string PassportNo { get; }
public string Nationality { get; }
public Passenger(string name, string lastName, string passportNo, string nationality)
{
this.Name = name;
this.LastName = lastName;
this.PassportNo = passportNo;
this.Nationality = nationality;
}
public static int CompareByName(Passenger passenger1, Passenger passenger2)
{
return String.Compare(passenger1.Name, passenger2.Name);
}
public static int CompareByLastName(Passenger passenger1, Passenger passenger2)
{
return String.Compare(passenger1.LastName, passenger2.LastName);
}
public static int CompareNationality(Passenger passenger1, Passenger passenger2)
{
return String.Compare(passenger1.Nationality, passenger2.Nationality);
}
}
public class TestPassengerSort
{
Passenger p1 = new Passenger("Johon", "Floid", "A123456789", "USA");
Passenger p2 = new Passenger("Jo", "Sina", "A987463215", "UAE");
Passenger p3 = new Passenger("Ped", "Zoola", "A987855215", "Italy");
public void SortThem()
{
Passenger[] passengers = new Passenger[] { p1, p2, p3 };
List<Passenger> passengerList = new List<Passenger> { p1, p2, p3 };
Array.Sort(passengers, Passenger.CompareByName);
Array.Sort(passengers, Passenger.CompareByLastName);
Array.Sort(passengers, Passenger.CompareNationality);
passengerList.Sort(Passenger.CompareByName);
passengerList.Sort(Passenger.CompareByLastName);
passengerList.Sort(Passenger.CompareNationality);
}
}
So you can implement your sort structure by using Composition delegate.