我认为你的方法不正确。你并不是在排序字符串,而是在排序被误解为字符串的结构化对象(有人恰当地称之为
"stringly typed"反模式)。你的需求表明你知道这个结构,但它没有在数据结构
List<string[]>
中表示出来,这使得你的生活变得困难。你应该将该结构解析成实际类型(结构体或类),然后对其进行排序。
enum PrefixCode { MW1, FW, DN, MWSTX1CK, MWSTX2FF, }
enum TheseLetters { Q, J, C, E, I, A, }
struct CardRecord : IComparable<CardRecord> {
public readonly PrefixCode Code;
public readonly TheseLetters Letter;
public readonly uint Number;
public CardRecord(string input) {
Code = ParseEnum<PrefixCode>(ref input);
Letter = ParseEnum<TheseLetters>(ref input);
Number = uint.Parse(input);
}
static T ParseEnum<T>(ref string input) {
foreach(T val in Enum.GetValues(typeof(T))) {
if(input.StartsWith(val.ToString())) {
input = input.Substring(val.ToString().Length);
return val;
}
}
throw new InvalidOperationException("Failed to parse: "+input);
}
public int CompareTo(CardRecord other) {
var codeCmp = Code.CompareTo(other.Code);
if (codeCmp!=0) return codeCmp;
var letterCmp = Letter.CompareTo(other.Letter);
if (letterCmp!=0) return letterCmp;
return Number.CompareTo(other.Number);
}
public override string ToString() {
return Code.ToString() + Letter + Number.ToString("00");
}
}
使用上述内容处理您的示例的程序可能如下所示:
static class Program {
static void Main() {
var inputStrings = new []{ "MW1E10", "MWSTX2FFI06", "FWQ02", "MW1Q04", "MW1Q05",
"FWI01", "MWSTX2FFA01", "DNC03", "MWSTX1CKC02", "MWSTX2FFI03", "MW1I06" };
var outputStrings = inputStrings
.Select(s => new CardRecord(s))
.OrderBy(c => c)
.Select(c => c.ToString());
Console.WriteLine(string.Join("\n", outputStrings));
}
}
这将生成与您示例中相同的排序。在真实代码中,我建议您根据它们所代表的内容对类型进行命名,而不是例如 `TheseLetters`。
这种使用了真正的解析步骤的解决方案更优秀,因为几乎可以肯定在某个时候您会想要对该数据执行更多操作,这使得您可以轻松地访问数据的组件。此外,这对于未来的维护者来说也是可以理解的,因为排序背后的原因是有些清楚的。相比之下,如果您选择进行复杂的基于字符串的处理,往往很难理解发生了什么(尤其是如果它是一个更大的程序的一部分,而不仅仅是这里的小例子)。
创建新类型是简单的。如果您的方法的返回值不完全 "适合" 存在的类型,则只需创建一个新类型,即使这意味着成千上万个类型也可以。