List <> OrderBy Alphabetical Order と同様に、1つの要素でソートしてから、別の要素でソートします。機能的に同等なものを達成したい
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で機能するソリューションを歓迎します。
すべてのメンバーを比較する場合、安定したソートは必要ないことに注意してください。要求された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オブジェクトをそのまま使用したい場合を除きます。
LINQ OrderBy
および ThenBy
(または必要に応じてThenByDescending
)を使用できる.Netのバージョンの場合:
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 answer を参照してください。
IComparer インターフェイスを実装する必要があります。 こちらが良い投稿です サンプルコード付き。
トリックは、安定したソートを実装することです。テストデータを含めることができるWidgetクラスを作成しました。
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 . . .
これはおそらく匿名のデリゲートでクリーンアップできますが、それはあなたにお任せします。
EDIT:そして、NoBugzは匿名メソッドの力を示しています...
これはあなたを助けるかもしれません、 C#汎用リストをソートする方法
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)));