在使用整数值对字符串列表进行排序时,我遇到了一个奇怪的问题。但是,某些值可能会以某些字符作为前缀。
e.g。
// B1, 5, 50, A10, 7, 72, B3, A1, A2
基本上有页码,应按如下方式排序:
// A1, A2, A10, B1, B3, 5, 7, 50, 72
但是如果我使用默认字符串排序,那么这些将按照
进行排序// A1, A10, A2, B1, B3, 5, 50, 7, 72
C#中的任何解决方案?
答案 0 :(得分:17)
您正在寻找 Alphanum algorithm 。幸运的是,已经存在许多实现。请参阅 here 。
答案 1 :(得分:5)
这就是我为我们的应用程序解决它的方式,顺序就像在windows目录中一样:
public class NaturalSortComparer : IComparer<string>
{
public int Compare(string x, string y)
{
return StrCmpLogicalW(x, y);
}
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern int StrCmpLogicalW(string x, string y);
}
用法:
NaturalSortComparer comparer = new NaturalSortComparer();
return comparer.Compare(string1, string2);
但它可能不完全是你想要的:
// A1,A2,A10,B1,B3,5,7,50,72
这将给出
// 5,7,50,72,A1,A2,A10,B1,B3
答案 2 :(得分:3)
您正在寻找的是自然排序。
杰夫阿特伍德曾在他的博客上发表了一篇很棒的文章,解释了这个概念,并以你可以采用的算法链接到其他各种来源。
答案 3 :(得分:1)
这是一个自定义比较器,它将按您所需的顺序排序。 请注意,此代码中没有错误/健全性检查:它假定所有字符串的格式都正确。
public class MyComparer : IComparer<string>
{
public int Compare(string x, string y)
{
Match xMatch = Regex.Match(x, @"^(\D*)(\d+)$");
Match yMatch = Regex.Match(y, @"^(\D*)(\d+)$");
string xChars = xMatch.Groups[1].Value;
string yChars = yMatch.Groups[1].Value;
if ((xChars.Length == 0) && (yChars.Length > 0))
{
return 1;
}
else if ((xChars.Length > 0) && (yChars.Length == 0))
{
return -1;
}
else
{
int charsResult = xChars.CompareTo(yChars);
return (charsResult != 0)
? charsResult
: int.Parse(xMatch.Groups[2].Value)
.CompareTo(int.Parse(yMatch.Groups[2].Value));
}
}
}
您可以像这样使用它:
List<string> testList =
new List<string>() { "B1","5","50","A10","7","72","B3","A1","A2" };
testList.Sort(new MyComparer()); // A1, A2, A10, B1, B3, 5, 7, 50, 72
答案 4 :(得分:0)
好吧,你总是可以调用Win32 API函数StrCmpLogicalW
,它完全符合你的需要(它是Explorer用来排序文件名的东西)。唯一可能的缺点是排序不区分大小写。
答案 5 :(得分:0)
不确定性能,确定可以优化,但它可以完成工作:
string[] sort(string[] data)
{
return data
.OrderBy(s => Regex.Match(s, @"^\D").Length == 0)
.ThenBy(s => Regex.Match(s, @"\D*").Value)
.ThenBy(s => Int32.Parse(Regex.Match(s, @"\d+").Value)).ToArray();
}
var result = sort(new string[] { "B1", "5", "50", "A10", "7", "72", "B3", "A1", "A2" });