Danh sách C # <> Sắp xếp theo x rồi đến y


88

Tương tự như List <> OrderBy theo thứ tự bảng chữ cái , chúng ta muốn sắp xếp theo một phần tử, rồi đến phần tử khác. chúng tôi muốn đạt được chức năng tương đương với

SELECT * from Table ORDER BY x, y  

Chúng tôi có một lớp chứa một số hàm sắp xếp và chúng tôi không gặp vấn đề gì khi sắp xếp theo một phần 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 thứ sau 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

Sắp xếp ổn định sẽ được ưu tiên hơn, nhưng không bắt buộc. Giải pháp hoạt động cho .Net 2.0 được hoan nghênh.


@Bolu Tôi đã xóa thẻ một cách rõ ràng để tạo cho phiên bản bài đăng những câu trả lời độc đoán và cập nhật để khớp với điều đó. Cân nhắc thực hiện chỉnh sửa làm rõ 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.
Alexei Levenkov

Xin lỗi @AlexeiLevenkov, không chú ý lắm, vui lòng quay lại.
Bolu

ĐỒNG Ý. Đã hoàn nguyên thay đổi.
Alexei Levenkov

Câu hỏi này đã được cập nhật để bao gồm tất cả các phiên bản .Net từ bản gốc chỉ 2.0 - chứa một số câu trả lời thay thế cho các khuôn khổ và yêu cầu khác nhau - hãy kiểm tra tất cả để xem cái nào phù hợp với yêu cầu của bạn hơn.
Alexei Levenkov

Câu trả lời:


98

Hãy nhớ rằng bạn không cần một sự sắp xếp ổn định nếu bạn so sánh tất cả các thành viên. 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);
     });
 }

Xin lưu ý rằng giải pháp 2.0 này vẫn được ưa chuộng hơn giải pháp Linq 3.5 phổ biến, nó thực hiện sắp xếp tại chỗ và không có yêu cầu lưu trữ O (n) của phương pháp Linq. Tất nhiên, trừ khi bạn muốn đối tượng Danh sách ban đầu được giữ nguyên.


156

Đối với các phiên bản .Net nơi bạn có thể sử dụng LINQ OrderByThenBy(hoặc ThenByDescendingnế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), hãy xem câu trả lời của Hans Passant cho câu hỏi này.


2
Từ một bài đăng câu trả lời khác của phoog tại đây: stackoverflow.com/questions/9285426/… 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 giữ lại thứ tự ban đầu cho một số mục đích khác; nó khá lãng phí nhiều bộ nhớ hơn sắp xếp danh sách tại chỗ
dreamerkumar


5

Bí quyết là thực hiện một loại ổn định. Tôi đã tạo một lớp Widget 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 IComp so sánh được, vì vậy nó có thể được sắp xếp không ổn định theo List.Sort ().

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

Tôi đã mượn phương pháp 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 điều này vào lớp trợ giúp sắp xếp mà bạn đã đề cập trong câu hỏi của mình.

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ó xuất ra:

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

Điều này có thể được làm sạch với một số đại biểu ẩn danh, nhưng tôi sẽ để điều đó cho bạn.

CHỈNH SỬA : Và NoBugz thể hiện sức mạnh của các phương pháp ẩn danh ... vì vậy, hãy coi tôi là trường cũ hơn: P



1

Tôi đã gặp sự cố trong đó 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. Giải pháp sắp xếp 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)));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.