我认为您的处理方法不正确。您不是对字符串进行排序,而是在对被错误表示为字符串的结构化对象进行排序(有人恰当地将这种反模式命名为"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) { //assumes non-overlapping prefixes
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。
这个解决方案 - 具有真正的解析步骤 - 非常出色,因为它几乎可以肯定您在某些时候会想要对这些数据做更多的事情,这使您可以轻松地实际访问数据的组成部分。此外,对于未来的维护者来说,这是可以理解的,因为排序背后的原因 有点清楚。相比之下,如果您选择进行复杂的基于字符串的处理,通常很难理解正在发生的事情(尤其是如果它是更大程序的一部分,而不是像这里这样的小例子)。
制作新类型很便宜。如果您的方法的返回值不太“适合”现有类型,只需创建一个新类型,即使这意味着有 1000 种类型。