2008-11-14 38 views
83

Tương tự như List<> OrderBy Alphabetical Order, chúng tôi muốn sắp xếp theo một phần tử, sau đó chọn một phần tử khác. chúng tôi muốn đạt được chức năng tương đương củaC# Danh sách <> Sắp xếp theo x rồi y

SELECT * from Table ORDER BY x, y 

Chúng tôi có một lớp có chứa một số chức năng phân loại và chúng tôi không phân loại vấn đề theo một yếu tố.
Ví dụ:

public class MyClass { 
    public int x; 
    public int y; 
} 

List<MyClass> MyList; 

public void SortList() { 
    MyList.Sort(MySortingFunction); 
} 

Và chúng tôi có những điều sau đây trong danh sách:

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 

Ổn định loại sẽ là một lợi thế, nhưng không bắt buộc. Giải pháp làm việc cho .Net 2.0 được chào đón.

+0

@Bolu Tôi đã gỡ bỏ một cách rõ ràng thẻ để thực hiện bài bản câu trả lời thuyết bất khả tri và được cập nhật để phù hợp đó. Cân nhắc thực hiện chỉnh sửa rõ ràng trong câu hỏi thay vì khôi phục thẻ nếu bạn cho rằng 4.0/2.0 không đủ nổi bật. –

+0

Xin lỗi @AlexeiLevenkov, đã không chú ý nhiều, vui lòng quay lại. – Bolu

+0

OK. Đã hoàn nguyên thay đổi. –

Trả lời

97

Hãy nhớ rằng bạn không cần sắp xếp ổn định nếu bạn so sánh tất cả các thành viên. Các giải pháp 2.0, theo yêu cầu, có thể trông như thế này:

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 lưu ý rằng giải pháp 2.0 này vẫn còn thích hợp hơn so với giải pháp phổ biến 3,5 LINQ, nó thực hiện một loại tại chỗ và không có O (n) yêu cầu lưu trữ của phương pháp tiếp cận LINQ. Trừ khi bạn thích đối tượng List ban đầu bị ảnh hưởng.

150

Đối với các phiên bản của Net nơi bạn có thể sử dụng LINQ OrderByThenBy (hoặc ThenByDescending nếu cần):

using System.Linq; 
.... 
List<SomeClass>() a; 
List<SomeClass> b = a.OrderBy(x => x.x).ThenBy(x => x.y).ToList(); 

Lưu ý: đối với Net 2.0 (hoặc nếu bạn không thể sử dụng LINQ) xem Hans Passant answer cho câu hỏi này.

+2

Từ một bài trả lời khác của phoog ở đây: http://stackoverflow.com/questions/9285426/orderby-and-list-vs-iorderedenumerable Nó tạo ra một danh sách khác với các mục gốc theo thứ tự mới. Điều này chỉ hữu ích nếu bạn cần duy trì thứ tự ban đầu cho một số mục đích khác; nó thay vì lãng phí bộ nhớ hơn là phân loại danh sách tại chỗ – dreamerkumar

+0

Chú ý: ThenBy được đánh giá ngay cả khi nó không được sử dụng ... –

5

Bí quyết là triển khai loại ổn định. Tôi đã tạo một lớp Tiện ích con có thể chứa dữ liệu thử nghiệm của bạn:

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; 
    } 
} 

Tôi đã triển khai IComparable, do đó, nó có thể được sắp xếp không ổn định bởi List.Sort().

Tuy nhiên, tôi cũng đã triển khai phương pháp tĩnh So sánh, có thể được chuyển làm đại biểu cho phương thức tìm kiếm.

Tôi mượn cách sắp xếp chèn này từ 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; 
      } 
    } 

Bạn sẽ đặt này trong lớp giúp đỡ loại mà bạn đề cập trong câu hỏi của bạn.

Bây giờ, để sử dụng nó:

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); 
     } 
    } 

Và nó ra:

0:1 
0:2 
1:1 
1:2 
Press any key to continue . . . 

này có thể có thể được làm sạch với một số đại biểu vô danh, nhưng tôi sẽ rời khỏi đó tùy thuộc vào bạn.

EDIT: Và NoBugz thể hiện sức mạnh của các phương thức nặc danh ...vì vậy, hãy xem xét trường cũ của tôi: P

+0

Wow, cảm ơn Jonathan, trên và hơn thế nữa! –

1

Tôi gặp sự cố khi OrderBy và ThenBy không cho tôi kết quả mong muốn (hoặc tôi không biết cách sử dụng chúng một cách chính xác).

Tôi đã đi với một danh sách.Các giải pháp tương tự như thế này.

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))); 
Các vấn đề liên quan