C#リスト<> x、yの順に並べ替え


88

List <> OrderBy Alphabetical Orderと同様に、ある要素で並べ替え、次に別の要素で並べ替えます。同等の機能を実現したい

SELECT * from Table ORDER BY x, y  

いくつかの並べ替え関数を含むクラスがあり、1つの要素で並べ替える問題はありません。
例えば:

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 2014年

申し訳ありませんが、@ AlexeiLevenkov、あまり注意を払っていませんでした。お気軽にロールバックしてください。
ボル

OK。変更を元に戻しました。
Alexei Levenkov 14年

この質問は、元のJust 2.0からの.Netのすべてのバージョンをカバーするように更新されました-異なるフレームワークおよび要件に対するいくつかの代替回答が含まれています-すべてをチェックして、どれが要件に適しているかを確認してください。
Alexei Levenkov、2014年

回答:


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ソリューションよりも依然として望ましいことに注意してください。インプレースソートを実行し、LinqアプローチのO(n)ストレージ要件はありません。もちろん、元のListオブジェクトをそのままにしたくない場合。


156

LINQ OrderByを使用できるバージョンの.Netの場合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()によって不安定にソートされる可能性があります。

ただし、静的メソッドCompareも実装しました。これはデリゲートとして検索メソッドに渡すことができます。

この挿入ソートメソッドを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.