我有一个要从枚举中提取的字符串列表,我需要按字母顺序排序,然后按数字排序,有些字符串没有数字,这些字符串应该在列表的末尾。
List =
"Incl 11
Incl 12
Excl 4
Incl 3
Other
Incl 4
Incl 10
Incl 11
Excl 10
Incl 1
Incl 2
Withdrew Col
Excl 1
Excl 2
Excl 3
Follow Up
"
到目前为止,我已经知道了,但是它只是按数字排序,而不是按字母顺序排序,任何帮助将不胜感激。
var test = Enum.GetValues(typeof(Reason))
.Cast<Reason>()
.Select(sc => new SelectListItem { Value = ((int)sc).ToString(), Text = sc.GetDisplayName() })
.OrderBy(s => s.Text, new MyNumberComparer())
.ToList();
class MyNumberComparer : IComparer<string>
{
public int Compare(string x, string y)
{
var xResultString = Regex.Match(x, @"\d+").Value;
var yResultString = Regex.Match(y, @"\d+").Value;
int xVal, yVal;
var xIsVal = int.TryParse(xResultString, out xVal);
var yIsVal = int.TryParse(yResultString, out yVal);
if (xIsVal && yIsVal)
return xVal.CompareTo(yVal);
if (!xIsVal && !yIsVal)
return x.CompareTo(y);
if (xIsVal)
return -1;
return 1;
}
}
编辑最终输出应为:
List =
"Excl 1
Excl 2
Excl 3
Excl 4
Excl 10
Incl 1
Incl 2
Incl 3
Incl 4
Incl 10
Incl 11
Incl 12
Follow Up
Other
Withdrew Col
"
答案 0 :(得分:1)
您快到了。如果值的非数字部分不相同,则仅需要比较非数字部分。只需将这些行放在比较方法的开头即可。
var xstring = Regex.Match(x, @".+?(?=\d+)").Value; //extract non-digit part
var ystring = Regex.Match(y, @".+?(?=\d+)").Value; //extract non-digit part
if (!string.IsNullOrEmpty(xstring) && !string.IsNullOrEmpty(ystring))
{
var comp = xstring.CompareTo(ystring);
if (comp != 0)
{
return comp;
}
}
答案 1 :(得分:0)
以下是IComparer
的实现,它将为您带来想要的东西
class MyNumberComparer : IComparer<string> {
public static Tuple<string, int?> SplitString(string s) {
var x = s.LastIndexOf(' ');
return x == -1 || x == s.Length - 1 || !int.TryParse(s.Substring(x + 1), out int n) ?
Tuple.Create(s, (int?)null) : Tuple.Create(s.Substring(0, x), (int?)n);
}
public int Compare(string str1, string str2) {
if (string.Compare(str1, str2) == 0)
return 0;
var str1Items = SplitString(str1);
var str2Items = SplitString(str2);
var prefixCompare = string.Compare(str1Items.Item1, str2Items.Item1);
if (str1Items.Item2 == null && str1Items.Item2 == null)
return prefixCompare;
if (str1Items.Item2 == null)
return 1;
if (str2Items.Item2 == null)
return -1;
return prefixCompare == 0 ? (int)(str1Items.Item2 - str2Items.Item2) : prefixCompare;
}
}
我已经根据您在问题中提到的问题(以空格分隔的数字)为基础,但是您可以更改SplitString
的实现,以反映将传入的字符串分解为字符串和数字或null的情况。
如果您希望以特殊方式(例如不区分大小写的方式)进行字符串比较,则可以更新string.Compare
代码中的MyNumberComparer.Compare
调用以反映出来。
答案 2 :(得分:0)
这是一个基于正则表达式组的简单解决方案。经过测试,它可以为您提供所需的结果。绝对不漂亮:
class Comparer : IComparer<string> {
static Regex Matcher = new Regex(@"([^\d]+)(\d+)");
public int Compare(string x, string y) {
var xMatch = Matcher.Match(x);
var yMatch = Matcher.Match(y);
if (xMatch.Success != yMatch.Success)
return xMatch.Success ? -1 : 1;
if (!xMatch.Success)
return string.Compare(x, y);
if (xMatch.Groups[1].Value != yMatch.Groups[1].Value)
return string.Compare(xMatch.Groups[1].Value, yMatch.Groups[1].Value);
return (int.Parse(xMatch.Groups[2].Value) - int.Parse(yMatch.Groups[2].Value)) < 0 ? -1 : 1;
}
}
如果您在一个字符串中有多个数字,上帝会帮助您。在这种情况下,您必须更改正则表达式模式以在字符串末尾仅查找数字。抱歉,我对此很懒。