ネタ元 → 5つのDateTime変数から、直近のものを選び出す方法
string[] data = {
"0", "00", "000", "0000", "00000",
"1", "11", "111", "1111", "11111",
"2", "22", "222", "2222", "22222",
"3", "33", "333", "3333", "33333",
};
こんなデータを"文字列の長さ"順に並べ替えます。
Array.Sort(data,delegate (string x, string y) { return x.Length - y.Length;});
Console.WriteLine("Array.Sort");
foreach ( string item in data ) Console.WriteLine(item);
僕の環境ではこんな結果となりました。
1
2
0
3
22
33
11
00
000
222
...
確かに文字列長の順にはなってますけど、キレイじゃありません。
等値な二つを並べるとき、もともとの順序を保つソートを"安定なソート:stable sort"
と称しています。 Array.Sortは安定なソートじゃないんですな。
安定なソートを実現する(でもちょっと重い)には、添え字ごとソートしちゃえばいぃです。
つまり、要素を比較して等しかったときは添え字の若い方を小さいとするわけっす。
ちょいちょいとこしらえてみましょ。
using System;
// 添え字つきデータ
struct Indexed<T> : IComparable {
public T data;
public int index;
public Indexed(T d, int i) { data = d; index = i; }
public static Comparison<T> compare;
// 比較結果が0(等値)のときは添え字を比較する
public int CompareTo(object other) {
int result = compare(data, ((Indexed<T>)other).data);
if ( result == 0 ) result = index - ((Indexed<T>)other).index;
return result;
}
}
public class Program {
// 安定なソート
static public void StableSort<T>(T[] array, Comparison<T> comp) {
Indexed<T>.compare = comp;
Indexed<T>[] iarray = new Indexed<T>[array.Length];
// 添え字つきデータをこしらえ
for ( int i = 0; i < array.Length; ++i ) {
iarray[i] = new Indexed<T>(array[i],i);
}
// ソートして
Array.Sort(iarray);
// 差し戻す
for ( int i = 0; i < array.Length; ++i ) {
array[i] = iarray[i].data;
}
}
public static void Main() {
string[] master = {
"0", "00", "000", "0000", "00000",
"1", "11", "111", "1111", "11111",
"2", "22", "222", "2222", "22222",
"3", "33", "333", "3333", "33333",
};
string[] data;
data = (string[])master.Clone();
Array.Sort(data,delegate (string x, string y) { return x.Length - y.Length;});
Console.WriteLine("Array.Sort");
foreach ( string item in data ) Console.WriteLine(item);
data = (string[])master.Clone();
StableSort(data,delegate (string x, string y) { return x.Length - y.Length;});
Console.WriteLine("StableSort");
foreach ( string item in data ) Console.WriteLine(item);
}
}