I have a List<Expense> myList where expense contains 2 fields: decimal Amount and a Status ItemStatus. Status is an enum {Paid, DueSoon, DueToday, Overdue, Unpaid}.
I was trying to sort the list in ascending or descending order however Status.Unpaid needs to always appear last in either ascending or descending order.
Using myList.Sort((x, y) => comparer.Compare(x.ItemStatus, y.ItemStatus)) along with my comparer worked well.
However, after sorting the list by ItemStatus I also wanted to sort the list by Amount. So I decided to use myList = myList.OrderBy(x => x.ItemStatus, comparer).ThenBy(x => x.Amount).ToList() this resulted in an infinite loop somewhere.
The infinite loop was still there when i removed the .ThenBy() method entirely.
I added a static counter to my comparer to try and debug and the OrderBy() method used the comparer 90 times on a list of 30 expenses before entering the infinite loop.
This is my comparer:
class StatusComparer : IComparer<Status>
{
public bool IsAscending { get; private set; } = true;
public StatusComparer(bool isAscending)
{
IsAscending = isAscending;
}
public int Compare(Status x, Status y)
{
if (IsUnpaid(x)) { return IsAscending? 1 : -1; }
if (IsUnpaid(y)) { return IsAscending ? -1 : 1; }
return x.CompareTo(y);
}
private static bool IsUnpaid(Status status)
{
return status.CompareTo(Status.Unpaid) == 0;
}
}
What am I doing wrong or how can I achieve what I'm trying to do?
Thanks in advance.
Your implementation of Compare is incorrect
public int Compare(Status x, Status y)
{
if (IsUnpaid(x)) { return IsAscending? 1 : -1; }
if (IsUnpaid(y)) { return IsAscending ? -1 : 1; }
return x.CompareTo(y);
}
Imagine, that we have IsAscending == true, IsUnpaid(x) == true and IsUnpaid(y) == true. In this case
x.Compare(y) == 1 // so x > y
y.Compare(x) == 1 // so y > x
That's why OrderBy may well enter into infinite loop (what is the right order for {x, y} collection if x > y and y > x?). You, probably, want
public int Compare(Status x, Status y) {
if (IsUnpaid(x)) {
if (!IsUnpaid(y))
return IsAscending ? -1 : 1; // x is UnPaid, y is Paid
}
else if (IsUnpaid(y)) {
return IsAscending ? 1 : -1; // x is Paid, y is UnPaid
}
// x and y either both Paid or unPaid
// If IsAscending should be taken into account, use it as below:
// return IsAscending ? x.CompareTo(y) : y.CompareTo(x);
return x.CompareTo(y);
}
Related
Similar to this question, I'm trying to iterate only distinct values of sub-string of given strings, for example:
List<string> keys = new List<string>()
{
"foo_boo_1",
"foo_boo_2,
"foo_boo_3,
"boo_boo_1"
}
The output for the selected distinct values should be (select arbitrary the first sub-string's distinct value):
foo_boo_1 (the first one)
boo_boo_1
I've tried to implement this solution using the IEqualityComparer with:
public class MyEqualityComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
int xIndex = x.LastIndexOf("_");
int yIndex = y.LastIndexOf("_");
if (xIndex > 0 && yIndex > 0)
return x.Substring(0, xIndex) == y.Substring(0, yIndex);
else
return false;
}
public int GetHashCode(string obj)
{
return obj.GetHashCode();
}
}
foreach (var key in myList.Distinct(new MyEqualityComparer()))
{
Console.WriteLine(key)
}
But the resulted output is:
foo_boo_1
foo_boo_2
foo_boo_3
boo_boo_1
Using the IEqualityComparer How do I remove the sub-string distinct values (foo_boo_2 and foo_boo_3)?
*Please note that the "real" keys are a lot longer, something like "1_0_8-B153_GF_6_2", therefore I must use the LastIndexOf.
Your current implementation has some flaws:
Both Equals and GetHashCode must never throw exception (you have to check for null)
If Equals returns true for x and y then GetHashCode(x) == GetHashCode(y). Counter example is "abc_1" and "abc_2".
The 2nd error can well cause Distinct return incorrect results (Distinct first compute hash).
Correct code can be something like this
public class MyEqualityComparer : IEqualityComparer<string> {
public bool Equals(string x, string y) {
if (ReferenceEquals(x, y))
return true;
else if ((null == x) || (null == y))
return false;
int xIndex = x.LastIndexOf('_');
int yIndex = y.LastIndexOf('_');
if (xIndex >= 0)
return (yIndex >= 0)
? x.Substring(0, xIndex) == y.Substring(0, yIndex)
: false;
else if (yIndex >= 0)
return false;
else
return x == y;
}
public int GetHashCode(string obj) {
if (null == obj)
return 0;
int index = obj.LastIndexOf('_');
return index < 0
? obj.GetHashCode()
: obj.Substring(0, index).GetHashCode();
}
}
Now you are ready to use it with Distinct:
foreach (var key in myList.Distinct(new MyEqualityComparer())) {
Console.WriteLine(key)
}
Your GetHashCode method in your equality comparer is returning the hash code for the entire string, just make it hash the substring, for example:
public int GetHashCode(string obj)
{
var index = obj.LastIndexOf("_");
return obj.Substring(0, index).GetHashCode();
}
For a more succinct solution that avoids using a custom IEqualityComparer<>, you could utilise GroupBy. For example:
var keys = new List<string>()
{
"foo_boo_1",
"foo_boo_2",
"foo_boo_3",
"boo_boo_1"
};
var distinct = keys
.Select(k => new
{
original = k,
truncated = k.Contains("_") ? k.Substring(0, k.LastIndexOf("_")) : k
})
.GroupBy(k => k.truncated)
.Select(g => g.First().original);
This outputs:
foo_boo_1
boo_boo_1
Similar to List<> OrderBy Alphabetical Order, we want to sort by one element, then another. we want to achieve the functional equivalent of
SELECT * from Table ORDER BY x, y
We have a class that contains a number of sorting functions, and we have no issues sorting by one element.
For example:
public class MyClass {
public int x;
public int y;
}
List<MyClass> MyList;
public void SortList() {
MyList.Sort( MySortingFunction );
}
And we have the following in the list:
Unsorted Sorted(x) Desired
--------- --------- ---------
ID x y ID x y ID x y
[0] 0 1 [2] 0 2 [0] 0 1
[1] 1 1 [0] 0 1 [2] 0 2
[2] 0 2 [1] 1 1 [1] 1 1
[3] 1 2 [3] 1 2 [3] 1 2
Stable sort would be preferable, but not required. Solution that works for .Net 2.0 is welcome.
For versions of .Net where you can use LINQ OrderBy and ThenBy (or ThenByDescending if needed):
using System.Linq;
....
List<SomeClass>() a;
List<SomeClass> b = a.OrderBy(x => x.x).ThenBy(x => x.y).ToList();
Note: for .Net 2.0 (or if you can't use LINQ) see Hans Passant answer to this question.
Do keep in mind that you don't need a stable sort if you compare all members. The 2.0 solution, as requested, can look like this:
public void SortList() {
MyList.Sort(delegate(MyClass a, MyClass b)
{
int xdiff = a.x.CompareTo(b.x);
if (xdiff != 0) return xdiff;
else return a.y.CompareTo(b.y);
});
}
Do note that this 2.0 solution is still preferable over the popular 3.5 Linq solution, it performs an in-place sort and does not have the O(n) storage requirement of the Linq approach. Unless you prefer the original List object to be untouched of course.
The trick is to implement a stable sort. I've created a Widget class that can contain your test data:
public class Widget : IComparable
{
int x;
int y;
public int X
{
get { return x; }
set { x = value; }
}
public int Y
{
get { return y; }
set { y = value; }
}
public Widget(int argx, int argy)
{
x = argx;
y = argy;
}
public int CompareTo(object obj)
{
int result = 1;
if (obj != null && obj is Widget)
{
Widget w = obj as Widget;
result = this.X.CompareTo(w.X);
}
return result;
}
static public int Compare(Widget x, Widget y)
{
int result = 1;
if (x != null && y != null)
{
result = x.CompareTo(y);
}
return result;
}
}
I implemented IComparable, so it can be unstably sorted by List.Sort().
However, I also implemented the static method Compare, which can be passed as a delegate to a search method.
I borrowed this insertion sort method from C# 411:
public static void InsertionSort<T>(IList<T> list, Comparison<T> comparison)
{
int count = list.Count;
for (int j = 1; j < count; j++)
{
T key = list[j];
int i = j - 1;
for (; i >= 0 && comparison(list[i], key) > 0; i--)
{
list[i + 1] = list[i];
}
list[i + 1] = key;
}
}
You would put this in the sort helpers class that you mentioned in your question.
Now, to use it:
static void Main(string[] args)
{
List<Widget> widgets = new List<Widget>();
widgets.Add(new Widget(0, 1));
widgets.Add(new Widget(1, 1));
widgets.Add(new Widget(0, 2));
widgets.Add(new Widget(1, 2));
InsertionSort<Widget>(widgets, Widget.Compare);
foreach (Widget w in widgets)
{
Console.WriteLine(w.X + ":" + w.Y);
}
}
And it outputs:
0:1
0:2
1:1
1:2
Press any key to continue . . .
This could probably be cleaned up with some anonymous delegates, but I'll leave that up to you.
EDIT: And NoBugz demonstrates the power of anonymous methods...so, consider mine more oldschool :P
This may help you,
How to Sort C# Generic List
I had an issue where OrderBy and ThenBy did not give me the desired result (or I just didn't know how to use them correctly).
I went with a list.Sort solution something like this.
var data = (from o in database.Orders Where o.ClientId.Equals(clientId) select new {
OrderId = o.id,
OrderDate = o.orderDate,
OrderBoolean = (SomeClass.SomeFunction(o.orderBoolean) ? 1 : 0)
});
data.Sort((o1, o2) => (o2.OrderBoolean.CompareTo(o1.OrderBoolean) != 0
o2.OrderBoolean.CompareTo(o1.OrderBoolean) : o1.OrderDate.Value.CompareTo(o2.OrderDate.Value)));
I currently have a list of coordinates that I need sorted. Each line represents Longitude, Latitude. I need to sort only on the Longitude.
It is stored in an string array:
string[] coords = fpdp.Coordinates.ToArray();
Here is the original list:
**LongLat**
98.63,85.02
43.08,79.07
26.97,70.88
18.8,62.3
13.47,53.5
8.57,44.8
3.58,36.35
-1.63,28.2
-6.93,20.33
-12.12,12.63
-17.17,5.02
-22.63,-2.25
-28.22,-9.43
-34.98,-15.7
-42.67,-21.08
-51.18,-25.62
-60.55,-29.12
-70.7,-31.12
-81.2,-31.18
-91.42,-29.72
-101.02,-26.97
-109.62,-22.85
-117.3,-17.83
-123.9,-11.9
-129.32,-5.05
-133.55,2.47
-136.9,10.3
-140.45,17.78
-144.75,24.98
-148.6,32.53
-152.02,40.37
-155.85,48.28
-160.8,56.27
-165.75,64.48
-172.62,72.78
171.35,80.83
98.93,85.17
Here is what I need it to look like. It is sorted by Large to small for positive numbers, and small to large for negative numbers. Only focusing on the first longitude coordinate:
**LongLat-Sorted**
171.35,80.83
98.93,85.17
98.63,85.02
43.08,79.07
26.97,70.88
18.8,62.3
13.47,53.5
8.57,44.8
3.58,36.35
-1.63,28.2
-6.93,20.33
-12.12,12.63
-17.17,5.02
-22.63,-2.25
-28.22,-9.43
-34.98,-15.7
-42.67,-21.08
-51.18,-25.62
-60.55,-29.12
-70.7,-31.12
-81.2,-31.18
-91.42,-29.72
-101.02,-26.97
-109.62,-22.85
-117.3,-17.83
-123.9,-11.9
-129.32,-5.05
-133.55,2.47
-136.9,10.3
-140.45,17.78
-144.75,24.98
-148.6,32.53
-152.02,40.37
-155.85,48.28
-160.8,56.27
-165.75,64.48
-172.62,72.78
How can I accomplish this in code? Any help would be great.
SOLUTION:
I tweaked this to the following, and it's working. Thanks a lot! :)
public class LongLatSort : IComparer
{
int IComparer.Compare(Object x, Object y)
{
string[] longLatParts1 = Convert.ToString(x).Split(',');
string[] longLatParts2 = Convert.ToString(y).Split(',');
var var1 = double.Parse(longLatParts1[0]);
var var2 = double.Parse(longLatParts2[0]);
if (var1 > var2)
{
return -1; // flipped for descending
}
else if (var1 < var2)
{
return 1; // flipped for descending
}
// secondary sort on latitude when values are equal
return var1 > var2 ? -1 : 1; // flipped for descending
}
}
Just finished tested this, seems to work.
class SimplePoint
{
public SimplePoint(string coord)
{
var coords = coord.Split(',').Select(s => double.Parse(s, System.Globalization.CultureInfo.InvariantCulture)).ToArray();
X = coords[0];
Y = coords[1];
}
public double X;
public double Y;
public override string ToString()
{
return X.ToString() + "," + Y.ToString();
}
}
static class LongLatParseAndSort
{
public static string SortedLongLat(string unsorted)
{
return unsorted
.Split(' ')
.Select(c => new SimplePoint(c))
.OrderByDescending(sp => sp.X)
.Select(sp => sp.ToString())
.Aggregate((a, b) => a += b);
}
}
How is this data stored? An array of Strings? or a 2-dimensional array or floats? or an Array of some structure with a lat and long? I'll assume its an array of LongLat since thats how you worded it.
EDIT I realized your subject title said string, so I added a constructor to convert from string to a LongLat.
Your desired result looks sorted descending on Longitude.
This code is untested, forgive me if it's not 100% but you get the idea.
// This is pretending to be the data structure you are using
public class LongLat {
private float mLongitude;
private float mLatitude;
// constructor from string for convenience
public LongLat(string longLatString ) {
string[] longLatParts = longLatString.Split(',');
mLongitude = float.Parse(longLatParts[0]);
mLatitude = float.Parse(longLatParts[1]);
}
public float Longitude {get; set; }
public float Latitude {get; set; }
}
// The sorter
public class LongLatSort : IComparer {
public int IComparer.Compare(object a, object b) {
LongLat o1=(LongLat)a;
LongLat o2=(LongLat)b;
if (o1.Longitude > o2.Longitude) {
return -1; // flipped for descending
} else if ( o1.Latitude < o2.Longitude ) {
return 1; // flipped for descending
}
// secondary sort on latitude when values are equal
return o1.Latitude > o2.Latitude ? -1 : 1; // flipped for descending
}
}
// now you should be able to use the sorter something like this?
// though best to not instantiate the Comparer every time but you get the idea
// EDIT: create your array of LongLats from strings first
Arrays.Sort( yourArrayofLongLats, new LongLastSort() );
I have a number of objects each with 3 numerical properties: "high", "low" and "tiebreaker". They are to be sorted as such: if an object's low is higher than another object's high, it appears before it in the list. Likewise if an object's high is lower than another's low, it appears later in the list. But in the case that two objects have conflicting ranges (eg one's high is between the other object's low and high), the tiebreaker property is considered wherein the object with the higher tiebreaker value gets placed earlier on the list.
I am specifically working with c#, but I think the ideas here are language agnostic enough such that code of any sort (no puns) would be welcome.
Also, I have worked on this myself. I have a nested for-loop that is just not working out for me so far. I'd give up some code but I'm on my phone and that makes it a chore. Besides, this is probably a fun one for you and you don't need my ugly code in your way anyhow.
Are you assuming that Min <= Tie <= Max? You do not say so in your question, and if you do not, the sort order is not well defined because it is not transitive. For instance, writing your ranges as [Min, Tie, Max], consider:
A: [5,-10, 6]
B: [0, 1, 10]
C: [2, 3, 4]
A < B (because they overlap and -10 < 1)
B < C (because they overlap and 1 < 3)
but A > C (because they don't overlap and 5 > 4)
If they are you can define a custom IComparer<Range> for your Range class, and pass it to any c# sort method.
Update and here's one such implementation.
public struct RangeWithTie<T> where T : IEquatable<T>, IComparable<T>
{
readonly T min;
readonly T max;
readonly T tie;
readonly bool isNonEmpty;
public static Range<T> Empty = new Range<T>();
public static IComparer<RangeWithTie<T>> CreateSortingComparer()
{
return new RangeWithTieComparer();
}
public RangeWithTie(T start, T tie, T end)
{
// Enfore start <= tie <= end
var comparer = Comparer<T>.Default;
if (comparer.Compare(start, end) > 0) // if start > end
{
throw new ArgumentOutOfRangeException("start and end are reversed");
}
else if (comparer.Compare(start, tie) > 0)
{
throw new ArgumentOutOfRangeException("tie is less than start");
}
else if (comparer.Compare(tie, end) > 0)
{
throw new ArgumentOutOfRangeException("tie is bigger than end");
}
else
{
this.min = start;
this.max = end;
this.tie = tie;
}
this.isNonEmpty = true;
}
public T Min { get { return min; } }
public T Max { get { return max; } }
public T Tie { get { return tie; } }
public bool IsEmpty { get { return !isNonEmpty; } }
public class RangeWithTieComparer : IComparer<RangeWithTie<T>>
{
#region IComparer<RangeWithTie<T>> Members
public int Compare(RangeWithTie<T> x, RangeWithTie<T> y)
{
// return x - y.
if (x.IsEmpty)
{
if (y.IsEmpty)
return 0;
else
return -1;
}
else if (y.IsEmpty)
{
return 1;
}
var comparer = Comparer<T>.Default;
if (comparer.Compare(y.Min, x.Max) > 0)
return -1;
else if (comparer.Compare(x.Min, y.Max) > 0)
return 1;
return comparer.Compare(x.Tie, y.Tie);
}
#endregion
}
public override string ToString()
{
if (IsEmpty)
return "Empty";
StringBuilder s = new StringBuilder();
s.Append('[');
if (Min != null)
{
s.Append(Min.ToString());
}
s.Append(", ");
if (Tie != null)
{
s.Append(Tie.ToString());
}
s.Append(", ");
if (Max != null)
{
s.Append(Max.ToString());
}
s.Append(']');
return s.ToString();
}
}
This could be used like so:
var sortedRanges = ranges.OrderBy(x => x, RangeWithTie<double>.CreateSortingComparer()).ToArray();
I didn't make the struct implement IComparer<RangeWithTie<T>> directly because ranges with identical comparisons aren't necessarily equal. For instance, [-1,0,1] and [-2,0,1] have identical comparisons but are not equal.
A quick solution, and a console application to test it. This method will return the larger of two objects. Just replace dynamic with the appropriate object type you need.
class Program
{
private static object Sort(dynamic first, dynamic second)
{
if (OverlapExists(first, second))
{
// Note: If tiebreakers are equal, the first will be returned:
return first.tiebreaker >= second.tiebreaker ? first : second;
}
else
{
// Note: Only need to test one value (just high); Since we know
// there is no overlap, the whole object (both high and low) must
// be either over or under that which it is compared to:
return first.high > second.high ? first : second;
}
}
private static bool OverlapExists(dynamic first, dynamic second)
{
return (first.low < second.high) && (second.low < first.high);
}
static void Main(string[] args)
{
dynamic first = new {name="first", high = 10,
tiebreaker = 5, low = 1 };
dynamic second = new {name="second", high = 15,
tiebreaker = 12, low = 11 };
dynamic third = new {name="third", high = 20,
tiebreaker = 9, low = 6 };
var firstResult = Sort(first, second);
var secondResult = Sort(first, third);
var thirdResult = Sort(second, third);
Console.WriteLine("1) " + first.ToString()
+ "\nVS: " + second.ToString());
Console.WriteLine("Winner: " + firstResult.name);
Console.WriteLine("\n2) " + first.ToString()
+ "\nVS: " + third.ToString());
Console.WriteLine("Winner: " + secondResult.name);
Console.WriteLine("\n3) " + second.ToString()
+ "\nVS: " + third.ToString());
Console.WriteLine("Winner: " + thirdResult.name);
Console.ReadKey();
}
}
Let’s say you have a List<T> (T being your objects with High-, Low- and Tie- Property), then you can use
list.Sort(…);
with a Comparison<T> as a Parameter. That’s a delegate that takes 2 of you objects and should return < 0, when the first instance of your object should be a head of the other instance or 0 if they are of equal order (or > 0 if the second second object should be ahead of first).
Or you could pass an custom comparer (implementing IComparer<T>) which does basically the same as the Comparison<T> but inform of an interface.
No matter what your logic is, you may implement IComparable to enable an Array or List's sorting capability. So, as the follow code shows,
public class MyStuff : IComparable<MyStuff>
{
public int High { get; set; }
public int Low { get; set; }
public int TieBreaker { get; set; }
public int CompareTo(MyStuff other)
{
// if an object's low is higher than another object's high,
// it appears before it in the list
if ((this.Low > other.High) ||
// if its high is between the other object's low and
// high then compare their tiebreaker
(this.High > other.Low && this.High < other.High &&
this.TieBreaker > other.TieBreaker))
return 1;
else if (this.Low == other.High)
return 0;
else
return -1;
}
}
The basic idea is CompareTo returns either 1 (move this before other), 0 (retain both positions) or -1 (move this after other), depending on your ordering logic.
See IComparable<T>
class DataObject : IComparable<DataObject>
{
public double High, Low, Tiebreaker;
public int CompareTo(DataObject obj)
{
// this doesn't seem to make sense as a range sort, but seems to match your question...
// low > another high
if (this.Low != obj.High)
return this.Low.CompareTo(obj.High);
// otherwise sort tiebreaker ascending
else this.TieBreaker.CompareTo(obj.TieBreaker);
}
}
used as
var items = new[] { new DataObject(1,2,3), new DataObject(4,5,6) };
Array.Sort<DataObject>(items);
// items is now sorted
Similar to List<> OrderBy Alphabetical Order, we want to sort by one element, then another. we want to achieve the functional equivalent of
SELECT * from Table ORDER BY x, y
We have a class that contains a number of sorting functions, and we have no issues sorting by one element.
For example:
public class MyClass {
public int x;
public int y;
}
List<MyClass> MyList;
public void SortList() {
MyList.Sort( MySortingFunction );
}
And we have the following in the list:
Unsorted Sorted(x) Desired
--------- --------- ---------
ID x y ID x y ID x y
[0] 0 1 [2] 0 2 [0] 0 1
[1] 1 1 [0] 0 1 [2] 0 2
[2] 0 2 [1] 1 1 [1] 1 1
[3] 1 2 [3] 1 2 [3] 1 2
Stable sort would be preferable, but not required. Solution that works for .Net 2.0 is welcome.
For versions of .Net where you can use LINQ OrderBy and ThenBy (or ThenByDescending if needed):
using System.Linq;
....
List<SomeClass>() a;
List<SomeClass> b = a.OrderBy(x => x.x).ThenBy(x => x.y).ToList();
Note: for .Net 2.0 (or if you can't use LINQ) see Hans Passant answer to this question.
Do keep in mind that you don't need a stable sort if you compare all members. The 2.0 solution, as requested, can look like this:
public void SortList() {
MyList.Sort(delegate(MyClass a, MyClass b)
{
int xdiff = a.x.CompareTo(b.x);
if (xdiff != 0) return xdiff;
else return a.y.CompareTo(b.y);
});
}
Do note that this 2.0 solution is still preferable over the popular 3.5 Linq solution, it performs an in-place sort and does not have the O(n) storage requirement of the Linq approach. Unless you prefer the original List object to be untouched of course.
The trick is to implement a stable sort. I've created a Widget class that can contain your test data:
public class Widget : IComparable
{
int x;
int y;
public int X
{
get { return x; }
set { x = value; }
}
public int Y
{
get { return y; }
set { y = value; }
}
public Widget(int argx, int argy)
{
x = argx;
y = argy;
}
public int CompareTo(object obj)
{
int result = 1;
if (obj != null && obj is Widget)
{
Widget w = obj as Widget;
result = this.X.CompareTo(w.X);
}
return result;
}
static public int Compare(Widget x, Widget y)
{
int result = 1;
if (x != null && y != null)
{
result = x.CompareTo(y);
}
return result;
}
}
I implemented IComparable, so it can be unstably sorted by List.Sort().
However, I also implemented the static method Compare, which can be passed as a delegate to a search method.
I borrowed this insertion sort method from C# 411:
public static void InsertionSort<T>(IList<T> list, Comparison<T> comparison)
{
int count = list.Count;
for (int j = 1; j < count; j++)
{
T key = list[j];
int i = j - 1;
for (; i >= 0 && comparison(list[i], key) > 0; i--)
{
list[i + 1] = list[i];
}
list[i + 1] = key;
}
}
You would put this in the sort helpers class that you mentioned in your question.
Now, to use it:
static void Main(string[] args)
{
List<Widget> widgets = new List<Widget>();
widgets.Add(new Widget(0, 1));
widgets.Add(new Widget(1, 1));
widgets.Add(new Widget(0, 2));
widgets.Add(new Widget(1, 2));
InsertionSort<Widget>(widgets, Widget.Compare);
foreach (Widget w in widgets)
{
Console.WriteLine(w.X + ":" + w.Y);
}
}
And it outputs:
0:1
0:2
1:1
1:2
Press any key to continue . . .
This could probably be cleaned up with some anonymous delegates, but I'll leave that up to you.
EDIT: And NoBugz demonstrates the power of anonymous methods...so, consider mine more oldschool :P
This may help you,
How to Sort C# Generic List
I had an issue where OrderBy and ThenBy did not give me the desired result (or I just didn't know how to use them correctly).
I went with a list.Sort solution something like this.
var data = (from o in database.Orders Where o.ClientId.Equals(clientId) select new {
OrderId = o.id,
OrderDate = o.orderDate,
OrderBoolean = (SomeClass.SomeFunction(o.orderBoolean) ? 1 : 0)
});
data.Sort((o1, o2) => (o2.OrderBoolean.CompareTo(o1.OrderBoolean) != 0
o2.OrderBoolean.CompareTo(o1.OrderBoolean) : o1.OrderDate.Value.CompareTo(o2.OrderDate.Value)));