C# List<> Sort by x then y
类似于list<>order by字母顺序,我们希望按一个元素排序,然后按另一个元素排序。我们希望实现
1 | SELECT * from Table ORDER BY x, y |
我们有一个包含许多排序函数的类,并且我们没有按一个元素排序的问题。例如:
1 2 3 4 5 6 7 8 9 10 | public class MyClass { public int x; public int y; } List<MyClass> MyList; public void SortList() { MyList.Sort( MySortingFunction ); } |
号
列表中有以下内容:
1 2 3 4 5 6 7 | 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 |
最好是稳定的种类,但不是必需的。欢迎使用适用于.NET 2.0的解决方案。
对于.NET版本,如果需要,可以使用linq
1 2 3 4 | using System.Linq; .... List<SomeClass>() a; List<SomeClass> b = a.OrderBy(x => x.x).ThenBy(x => x.y).ToList(); |
注意:对于.NET 2.0(或者如果您不能使用LINQ),请参见Hans Passant对这个问题的回答。
一定要记住,如果你比较所有成员,你不需要一个稳定的排序。根据要求,2.0解决方案可以如下所示:
1 2 3 4 5 6 7 8 | 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); }); } |
号
请注意,这个2.0解决方案仍然比流行的3.5 LINQ解决方案更可取,它执行就地排序,并且没有LINQ方法的O(N)存储要求。当然,除非您希望原始列表对象不受影响。
您需要实现IComparer接口。这里有一篇很好的文章,上面有示例代码。
诀窍是实现一个稳定的排序。我创建了一个小部件类,可以包含您的测试数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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; } } |
我实现了IComparable,所以它可以不稳定地按list.sort()排序。
但是,我还实现了静态方法比较,可以将其作为委托传递给搜索方法。
我从C 411借用了这个插入排序方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } } |
。
你可以把它放到你在问题中提到的分类助手类中。
现在,要使用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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); } } |
它输出:
1 2 3 4 5 | 0:1 0:2 1:1 1:2 Press any key to continue . . . |
。
这可能会被一些匿名代表清理掉,但我会由你来决定。
编辑:Nobugz展示了匿名方法的威力……所以,考虑一下我的老派:p
这对你有帮助,如何排序C通用列表
我有一个问题,orderby和thenby没有给我想要的结果(或者我只是不知道如何正确使用它们)。
我列出了一个清单,对解决方案进行类似这样的排序。
1 2 3 4 5 6 7 8 | 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))); |
。