私は学生が座っているようなクラスを持っています。私はB6 B7 B8 B9 B10 B11のような場所を持っています.FindAllをいくつかのクラス(1つのおっとバージョン)で使用すると、この順序で取得されます.
someclass.OrderBy(r => r.location);
その後、場所は B10 B11 B6 B7 B8 B9 になり、ここで何が問題になっていますか。その場合、orderBYを使用しないほうがよいのですが、問題の理由を教えてもらえますか?
独自のカスタム比較子を実装できます...
class CustomCompare : IComparer<string>
{
private static readonly char[] _digits = "0123456789".ToArray();
public int Compare(string a, string b)
{
//assuming alpha start, numeric end
var alphaA = a.TrimEnd(_digits);
var alphaB = b.TrimEnd(_digits);
var alphaCompareTo = alphaA.CompareTo(alphaB);
if (alphaCompareTo != 0)
{
return alphaCompareTo;
}
var numericA = int.Parse(a.Substring(alphaA.Length));
var numericB = int.Parse(b.Substring(alphaB.Length));
return numericA.CompareTo(numericB);
}
}
...そして、そのように使用します...
someclass.OrderBy(r => r.location, new CustomCompare());
これは、文字列が文字列として比較されているためです。 '1'
がより小さい'6'
ため、字句比較はその文字で停止します。
字句ソートではなく自然ソートが必要なようです。
あなたのlocation
プロパティ(またはフィールド)は文字列だと思いますか?
次のように書くこともできますComparer<>
:
sealed class LocationComparer : Comparer<string>
{
// expect strings like "B3" or "C26"
public override int Compare(string x, string y)
{
int result = x[0].CompareTo(y[0]);
if (result != 0)
return result;
result = ushort.Parse(x.Substring(1)).CompareTo(ushort.Parse(y.Substring(1)));
return result;
}
}
のように使いますsorted = someclass.OrderBy(r => r.location, new LocationComparer());
。
またはlocation
、タイプを次のスタイルのクラスに変更できます。
// this class inherits the IComparable implementation of Tuple`2
sealed class Location : Tuple<char, ushort>
{
public Location(char letter, ushort number)
: base(char.ToUpper(letter), number)
{
}
public Location(string locationString)
: this(letter: locationString[0], number: ushort.Parse(locationString.Substring(1)))
{
}
public override string ToString()
{
return Item1.ToString() + Item2.ToString();
}
}
Someclass
クラス内にlocation
は type がありLocation
ます。その後、オリジナルsorted = someclass.OrderBy(r => r.location);
が機能します。
どちらのソリューションも単なるスケッチです。いくつかのサニティチェックを追加したいと思うでしょう。
Order by は、数値順ではなく文字列順を使用します。
'B10' < 'B6'
各エントリは、文字ごとに比較されます。
'B10'
'B6'
^
これが重要な文字です (B も同じです)。'6' > '1'.
orderbyは正しく機能しています。文字列B10が文字列B11の前にあり、文字列B11がB6の前にあることに注意してください。
あなたが注文しようとしているList<string>
のではなく(またはそれが私が思うものです)、List<int>
In order to render numbers in strings lexicographically sortable, they'd need to be padded i.e. B01 < B06 < B10 as B6 is > B10 as it's done left to right. So your simple option is to pad if you know your upper bounds, otherwise you'll have to rethink a little.
それらは常に「X###」の形式になりますか?もしそうなら、あなたは使うことができます:
yourListObject.OrderBy(r => int.Parse(r.location.SubString(1)));
これは1つの回避策です。状況がはるかに複雑な場合は、新しく作成されたLocationクラスの比較オブジェクトも作成する必要があります。
自然な並べ替えアルゴリズムが必要です。Ian からこれを取得して、次のように呼び出します。
someclass.OrderBy(r => r.location, new EnumerableComparer<String>());