C # List <> เรียงตาม x แล้ว y


88

คล้ายกับList <> OrderBy Alphabetical Orderเราต้องการจัดเรียงตามองค์ประกอบหนึ่งจากนั้นอีกองค์ประกอบหนึ่ง เราต้องการบรรลุฟังก์ชันเทียบเท่าของ

SELECT * from Table ORDER BY x, y  

เรามีคลาสที่มีฟังก์ชันการเรียงลำดับจำนวนหนึ่งและเราไม่มีปัญหาในการจัดเรียงตามองค์ประกอบเดียว
ตัวอย่างเช่น:

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

List<MyClass> MyList;

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

และเรามีสิ่งต่อไปนี้ในรายการ:

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


@Bolu ฉันได้ลบแท็กอย่างชัดเจนเพื่อให้โพสต์เวอร์ชันที่เข้าใจได้ง่ายและอัปเดตคำตอบให้ตรง ลองทำการแก้ไขที่ชัดเจนในคำถามแทนการกู้คืนแท็กหากคุณคิดว่า 4.0 / 2.0 ไม่โดดเด่นเพียงพอ
Alexei Levenkov

ขออภัย @AlexeiLevenkov ไม่ได้ให้ความสนใจมากโปรดอย่าลังเลที่จะย้อนกลับ
Bolu

ตกลง. ยกเลิกการเปลี่ยนแปลง
Alexei Levenkov

คำถามนี้ได้รับการอัปเดตเพื่อให้ครอบคลุม. Net ทุกเวอร์ชันจากต้นฉบับเพียง 2.0 - มีคำตอบอื่น ๆ สำหรับกรอบงานและข้อกำหนดที่แตกต่างกัน - ตรวจสอบทั้งหมดเพื่อดูว่าข้อใดเหมาะกับความต้องการของคุณมากกว่ากัน
Alexei Levenkov

คำตอบ:


98

โปรดทราบว่าคุณไม่จำเป็นต้องมีการจัดเรียงที่มั่นคงหากคุณเปรียบเทียบสมาชิกทั้งหมด โซลูชัน 2.0 ตามที่ร้องขออาจมีลักษณะดังนี้:

 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 ที่เป็นที่นิยมโดยจะทำการจัดเรียงแบบแทนที่และไม่มีข้อกำหนดการจัดเก็บ O (n) ของวิธี Linq เว้นแต่คุณจะต้องการให้วัตถุรายการดั้งเดิมไม่ถูกแตะต้องแน่นอน


156

สำหรับเวอร์ชันของ. Net ที่คุณสามารถใช้ LINQ OrderByและThenBy(หรือThenByDescendingถ้าจำเป็น):

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
จากโพสต์คำตอบอื่นโดย phoog ที่นี่: stackoverflow.com/questions/9285426/… จะสร้างรายการอื่นด้วยรายการเดิมในลำดับใหม่ สิ่งนี้มีประโยชน์เฉพาะในกรณีที่คุณต้องการรักษาการสั่งซื้อเดิมไว้เพื่อวัตถุประสงค์อื่น มันค่อนข้างสิ้นเปลืองหน่วยความจำมากกว่าการจัดเรียงรายการในสถานที่
dreamerkumar

5

เคล็ดลับคือการใช้การจัดเรียงที่มั่นคง ฉันได้สร้างคลาสวิดเจ็ตที่สามารถมีข้อมูลการทดสอบของคุณ:

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 :

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

คุณจะใส่สิ่งนี้ไว้ในคลาสตัวช่วยการจัดเรียงที่คุณพูดถึงในคำถามของคุณ

ตอนนี้วิธีใช้:

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

และส่งออก:

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

สิ่งนี้อาจถูกลบล้างโดยผู้ได้รับมอบหมายที่ไม่ระบุชื่อ แต่ฉันจะฝากไว้ให้คุณ

แก้ไข : และ NoBugz แสดงให้เห็นถึงพลังของวิธีการที่ไม่ระบุชื่อ ... ดังนั้นลองพิจารณาโรงเรียนเก่าของฉันเพิ่มเติม: P



1

ฉันมีปัญหาที่ OrderBy และ ThenBy ไม่ได้ให้ผลลัพธ์ที่ต้องการ (หรือฉันไม่รู้วิธีใช้อย่างถูกต้อง)

ฉันไปกับรายการเรียงลำดับโซลูชันเช่นนี้

    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)));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.