我有一个字符串列表(包含housenumbers),如下所示:
List<string> myList = new List<string> { "11", "11a", "11 a", "11-1", "11a-1" };
myList.Sort(new MyComparer());
现在我想要将列表排序为{ "11", "11a", "11 a", "11a-1", "11-1" }
,这意味着首先是所有没有后缀的hosenumbers,然后是那些后面有一个字母然后是其他所有的hosenumbers。所以我将我的字符串拆分为前缀(实际数字)和后缀(数字本身后面的所有内容)。
private class MyComparer : IComparer<string>
{
protected virtual int compareHouseNumbers(string hnr1, string hnr2)
{
// ...
// split number and suffix
// ...
// housenumbers (integers) are also equal so let the suffix decide which one is greater
// the suffixes do not contain any spaces now
if (String.IsNullOrEmpty(suffix1)) return -1;
else if (String.IsNullOrEmpty(suffix2)) return 1;
// the following shell ensure that a letter comes "before" any other special char (such as "-" or "/")
if (Char.IsLetter(suffix1.FirstOrDefault()) && !Char.IsLetter(suffix2.FirstOrDefault())) return -1;
else if (!Char.IsLetter(suffix1.FirstOrDefault()) && Char.IsLetter(suffix2.FirstOrDefault())) return 1;
// if we have more complexity (compare 11a-1 with 11a-2) we use standard string-comparison
return String.Compare(suffix1, suffix2);
}
/// <inheritDoc/>
public int Compare(string lbz1, string lbz2)
{
return this.compareHouseNumbers(lbz1, lbz2);
}
}
但是我在根据这些后缀对列表进行排序时遇到了问题。我得到的列表是{"11", "11 a", "11a", "11-1", "11a-1"}
虽然互换的条目"11a"
和"11 a"
可以用于我们的目的,但我不明白为什么最后一个条目是"11a-1"
而不是{{1} }。我已经通过比较进行了调试,但显然这两个成员从未被直接比较,因此很难理解这里到底发生了什么。如果没有?{/ p>之前的"11-1"
,我该怎么办?
如果可能有更优雅的方式来实现这一目标,我会提出任何改进意见。
编辑:将输入拆分为实际数字和后缀主要是使用此正则表达式"a"
完成的。这导致整数部分(实际的housnumber)和该数字后面的字符串部分。之后我们只使用(\\d+)\\s*(\\S*)
(suffix1 = suffix1.Trim(' ', '-', '/');
适当地修剪后缀中的任何非字母数字字符。尽管如此,我们实际上并没有将suffix2
与-1
进行比较,而是{{1}与a-1
。但是,这不会改变结果本身的任何内容(因为1
和a-1
都在lecographically小于-1
)。
EDIT2:我删除了列表中的一些成员,以便只剩下两个有问题的成员:1
更改后,排序结果与预期一致:a
EDIT3:我刚刚更改了列表中成员的顺序(将List<string> myList = new List<string> { "11-1", "11a-1" };
放在列表的末尾)。现在结果也如预期。所以它似乎取决于列表中元素的初始顺序。很奇怪......
答案 0 :(得分:0)
尝试以下操作,你没有举例说明你如何拆分前缀和后缀,所以我做了一个:
private class MyComparer : IComparer<string>
{
private static readonly Regex matchRegex = new Regex(@"^(?<prefix>\d+)(?<spaces>\s*)(?<suffix>.*?)$");
private int match(string compare, out string prefix, out string suffix) {
var match= matchRegex.Match(compare);
prefix=match.Groups["prefix"].Value;
suffix=match.Groups["suffix"].Value;
return match.Groups["spaces"].Value.Length;
}
protected virtual int compareHouseNumbers(string hnr1, string hnr2)
{
// ...
// split number and suffix
// ...
string prefix1;
string prefix2;
string suffix1;
string suffix2;
var spaces1 = match(hnr1, out prefix1,out suffix1);
var spaces2 = match(hnr2, out prefix2,out suffix2);
Debug.WriteLine("Comparing '{0}' and '{1}'",suffix1,suffix2);
var prefixCompare = String.Compare(prefix1,prefix2);
if (prefixCompare != 0) {
return prefixCompare;
}
// housenumbers (integers) are also equal so let the suffix decide which one is greater
// the suffixes do not contain any spaces now
// FIX IS HERE!!!
// Previous code would compare "11" and "11" and return -1 which confuses the sort
if (String.IsNullOrEmpty(suffix1)) return (String.IsNullOrEmpty(suffix2)) ? 0 : -1;
else if (String.IsNullOrEmpty(suffix2)) return 1;
// the following shell ensure that a letter comes "before" any other special char (such as "-" or "/")
if (Char.IsLetter(suffix1.FirstOrDefault()) && !Char.IsLetter(suffix2.FirstOrDefault())) return -1;
else if (!Char.IsLetter(suffix1.FirstOrDefault()) && Char.IsLetter(suffix2.FirstOrDefault())) return 1;
// if we have more complexity (compare 11a-1 with 11a-2) we use standard string-comparison
var result = String.Compare(suffix1, suffix2);
// if the suffixes are equal sort on the number of spaces between prefix and suffix
if (result == 0) {
return (spaces1 - spaces2) <0 ? -1 : (spaces1 == spaces2) ? 0: 1;
}
return result;
}
/// <inheritDoc/>
public int Compare(string lbz1, string lbz2)
{
return this.compareHouseNumbers(lbz1, lbz2);
}
}