c# - 按数字顺序排列字母数字字符串,然后按前缀/后缀
问题描述
我有一个复杂的排序模式要复制,我的解决方案似乎有点笨拙。我的输入是一个数字列表,可以有几个字母作为后缀,前缀都是字母('aaa'、'aab'、'ac' 等)。我需要按数字排序,然后按后缀(如果有的话)排序,然后按前缀(如果有的话)排序。
例如
"a1a",
"5ac",
"1",
"12",
"2",
"11",
"5aa",
"3",
"5ab",
"a2b",
"abb11ca",
"1b",
"aba11ca"
将被排序为
1
a1a
1b
2
a2b
3
5aa
5ab
5ac
11
aba11ca
abb11ca
12
这是我使用 Linq 提出的解决方案。
static void Main(string[] args)
{
var arr = new []
{"b2","a1a","5ac","1","12","2","11","5aa","3","5ab","a1","a2b","abb11ca","1b","aba11ca"
};
var ordered = arr.Select(str => {
var parts = SplitIntoPrefixNumberSuffix(str);
var number = int.Parse(parts[1]);
return new { str, parts, number };
})
.OrderBy(x => x.number).ThenBy(x => x.parts[2]).ThenBy(x => x.parts[0])
.Select(x => x.str);
Console.WriteLine("sorted array: ");
foreach (var s in ordered)
{
Console.WriteLine("{0}", s);
}
Console.ReadLine();
}
public static string[] SplitIntoPrefixNumberSuffix(string str)
{
var numChar = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
var numLoc = str.IndexOfAny(numChar);
var nums = "";
foreach (var c in str)
{
if (char.IsDigit(c))
nums = nums + c;
}
Console.WriteLine("numLoc: {0}; nums: {1}", numLoc, nums.Count());
var prefix = str.Substring(0, numLoc);
var suffix = str.Substring(numLoc + nums.Count());
Console.WriteLine("prefix {0}; nums {1}; suffix {2}", prefix, nums, suffix);
return new[] { prefix, nums, suffix };
}
这是它的一个 .netfiddle:https ://dotnetfiddle.net/C7ZA0b 。
虽然它有效,但感觉这不是一个很好的解决方案。我对集合进行了多次迭代,我认为我应该使用自定义的可比性。
我以前从未写过 Comparable;我查看了Dot Net Pearls Alphanumeric Sorting并且可以遵循它,但还不足以对其进行修改以满足我的需要。
是否有 IComparable 我可以用来完成上述工作?关于一个学习如何写的好地方有什么建议吗?
解决方案
因此,您可以使用正则表达式命名组来拆分字符串的各个组件,然后按每个组件排序:
var regex = new Regex(@"^(?<pre>\D*)(?<num>\d+)(?<suff>\D*)$");
var ordered = data.Select(d => (match: regex.Match(d), value: d))
.Where(x => x.match.Success) //throw away anything that doesn't conform
.Select(x => (
x.value,
pre: x.match.Groups["pre"].Value,
num: int.Parse(x.match.Groups["num"].Value),
suff: x.match.Groups["suff"].Value))
.OrderBy(x => x.num)
.ThenBy(x => x.suff)
.ThenBy(x => x.pre)
.Select(x => x.value);
...但最终这与您的解决方案并没有什么不同。我真的看不出专业人士IComparer
将如何简化这一点。
如果您没有可用的元组(< C#7.0),请交换匿名类:
data.Select(d => new { match = regex.Match(d), value = d})
.Where(x => x.match.Success)
.Select(x => new {
x.value,
pre = x.match.Groups["pre"].Value,
num = int.Parse(x.match.Groups["num"].Value),
suff = x.match.Groups["suff"].Value})
.OrderBy(x => x.num)
.ThenBy(x => x.suff)
.ThenBy(x => x.pre)
.Select(x => x.value)
推荐阅读
- sql-server - 更新 Visual Studio 数据库项目中多个过程的生成操作
- sql - 对列中的每个值重复查询并合并所有结果
- c - 从函数返回结构到main.c?
- linux - Shell 脚本无法解析主机列表和主机未知
- python - 使用python在目录中查找文件,如果多个文件显示匹配,则决定打开哪个文件
- java - Android 通知不执行任何操作
- ffmpeg - 我可以在一个带有 ffmpeg 的命令中使用 -crf 和 -s 选项吗
- regex - 正则表达式字符串邮件
- docker - Bitbucket Android 管道在 gradlew 上总是失败
- node.js - Sequelize-typescript 'HasManyCreateAssociationMixin' 不是函数