我有一个字符串,其中包含以句点分隔的数字。当我排序它看起来像这样,因为它是一个字符串:(ascii char order)
3.9.5.2.1.1
3.9.5.2.1.10
3.9.5.2.1.11
3.9.5.2.1.12
3.9.5.2.1.2
3.9.5.2.1.3
3.9.5.2.1.4
等
我希望它像这样排序:(按数字顺序)
3.9.5.2.1.1
3.9.5.2.1.2
3.9.5.2.1.3
...
3.9.5.2.1.9
3.9.5.2.1.10
3.9.5.2.1.11
3.9.5.2.1.12
我知道我可以:
如果重复现有功能,我宁愿避免所有这些工作。 .net框架中的方法是否已经执行此操作?
答案 0 :(得分:4)
这是我的工作解决方案,它也处理不正确格式的字符串(例如包含文本)。
这个想法是获取两个字符串中的第一个数字并比较这些数字。如果匹配,请继续下一个号码。如果他们不这样做,我们就有了胜利者。如果这些数字不是一个数字,那么对该部分进行字符串比较,但尚未比较。
通过更改确定下一个数字的方式,可以很容易地使比较器与自然排序顺序完全兼容。
看那......刚刚找到this question。
比较者:
class StringNumberComparer : IComparer<string>
{
public int Compare(string x, string y)
{
int compareResult;
int xIndex = 0, yIndex = 0;
int xIndexLast = 0, yIndexLast = 0;
int xNumber, yNumber;
int xLength = x.Length;
int yLength = y.Length;
do
{
bool xHasNextNumber = TryGetNextNumber(x, ref xIndex, out xNumber);
bool yHasNextNumber = TryGetNextNumber(y, ref yIndex, out yNumber);
if (!(xHasNextNumber && yHasNextNumber))
{
// At least one the strings has either no more number or contains non-numeric chars
// In this case do a string comparison of that last part
return x.Substring(xIndexLast).CompareTo(y.Substring(yIndexLast));
}
xIndexLast = xIndex;
yIndexLast = yIndex;
compareResult = xNumber.CompareTo(yNumber);
}
while (compareResult == 0
&& xIndex < xLength
&& yIndex < yLength);
return compareResult;
}
private bool TryGetNextNumber(string text, ref int startIndex, out int number)
{
number = 0;
int pos = text.IndexOf('.', startIndex);
if (pos < 0) pos = text.Length;
if (!int.TryParse(text.Substring(startIndex, pos - startIndex), out number))
return false;
startIndex = pos + 1;
return true;
}
}
<强>用法:强>
public static void Main()
{
var comparer = new StringNumberComparer();
List<string> testStrings = new List<string>{
"3.9.5.2.1.1",
"3.9.5.2.1.10",
"3.9.5.2.1.11",
"3.9.test2",
"3.9.test",
"3.9.5.2.1.12",
"3.9.5.2.1.2",
"blabla",
"....",
"3.9.5.2.1.3",
"3.9.5.2.1.4"};
testStrings.Sort(comparer);
DumpArray(testStrings);
Console.Read();
}
private static void DumpArray(List<string> values)
{
foreach (string value in values)
{
Console.WriteLine(value);
}
}
<强>输出:强>
....
3.9.5.2.1.1
3.9.5.2.1.2
3.9.5.2.1.3
3.9.5.2.1.4
3.9.5.2.1.10
3.9.5.2.1.11
3.9.5.2.1.12
3.9.test
3.9.test2
blabla
答案 1 :(得分:3)
不,我不相信框架中有任何自动执行此操作的内容。您可以编写自己的IComparer<string>
实现,其中不会进行任何拆分,而是迭代两个字符串,只比较所需的数量(即只解析每个字符串的第一个数字,然后继续,如果有必要等)但我怀疑这将是非常繁琐。它还需要假设“1.2.3.4.5”与“1.3”相比如何(即值包含不同数量的数字)。
答案 2 :(得分:2)
由于您要对字符串进行的比较与.Net中通常比较字符串的方式不同,您必须使用自定义字符串字符串比较器
class MyStringComparer : IComparer<string>
{
public int Compare(string x, string y)
{
// your comparison logic
// split the string using '.' separator
// parse each string item in split array into an int
// compare parsed integers from left to right
}
}
然后您可以在OrderBy和Sort
等方法中使用比较器var sorted = lst.OrderBy(s => s, new MyStringComparer());
lst.Sort(new MyStringComparer());
这将为您提供所需的结果。如果没有,那么只需调整比较器。
答案 3 :(得分:2)
您要寻找的是自然排序顺序Jeff Atwood bloged about it and has links to implementations in different languages。 .NET Framework不包含实现。
答案 4 :(得分:0)
您是否可以使用0
将字段填充到前面相同的长度?如果是这样,那么你可以在字符串上使用直接的词典排序。否则,框架内置的这种方法不会自动执行此操作。如果填充不是一种选择,则必须实现自己的IComparer<string>
。
答案 5 :(得分:0)
不是真的,尽管你可以使用Regexes或Linq来避免过多的轮胎重新发明。请记住,使用内置的东西进行计算会花费你很多钱。
试试这个:
List<string> myList = GetNumberStrings();
myList.Select(s=>s.Split('.')).ToArray().
.Sort((a,b)=>RecursiveCompare(a,b))
.Select(a=>a.Aggregate(new StringBuilder(),
(s,sb)=>sb.Append(s).Append(".")).Remove(sb.Length-1, 1).ToString())
.ToList();
...
public int RecursiveCompare(string[] a, string[] b)
{
return RecursiveCompare(a,b,0)
}
public int RecursiveCompare(string[] a, string[] b, int index)
{
return index == a.Length || index == b.Length
? 0
: a[index] < b[index]
? -1
: a[index] > b[index]
? 1
: RecursiveCompare(a,b, index++);
}
不是最紧凑的,但它应该可以工作,你可以使用y-combinator使比较成为lambda。
答案 6 :(得分:0)
将每个字符串拆分为“。”,迭代组件并以数字方式对它们进行比较。
此代码还假设组件的数量是显着的(字符串'1.1.1'将大于'2.1'。这可以通过更改{{1}中的第一个if
语句来调整。下面的方法。
Compare
答案 7 :(得分:0)
您可以使用David Koelle的精彩AlphanumComparator
Alphanum natural sort algorithm。
代码:
OrderBy(o => o.MyString, new AlphanumComparator())
如果您要使用C#版本,请将其更改为:
AlphanumComparator : IComparer<string>
和
public int Compare(string x, string y)
答案 8 :(得分:-1)
除了像Jon所提到的那样实现你自己的IComparer之外,如果在数组上调用ToList(),你可以调用.Sort()方法并传入一个比较两个值的函数参数,如下所示:{{ 3}}