当我尝试使用IComparer<string>
进行排序时,至少需要进行100000次比较。
为什么?
public class PeriodComparer: IComparer<string>
{
int num = 0;
public int Compare(string x, string y)
{
var year1 = int.Parse(x.Substring(2));
var year2 = int.Parse(y.Substring(2));
if (year1 < year2)
return -1;
if (year1 > year2)
return 1;
var season1 = x.Substring(0, 2);
return season1 == "VT" ? -1 : 1;
}
}
我尝试用它来对数组字符串进行排序,如
var strings = new []
{"VT2010", "HT2010",
"VT2011", "HT2011",
"VT2012", "HT2012",
"VT2013", "HT2013",
"VT2014", "HT2014",
"VT2015", "HT2015",
"VT2016", "HT2016",
"VT2017", "HT2017"};
var comparer = new PeriodComparer();
var orderedPeriodNames = strings.OrderBy(x => x, comparer).ToList();
期望字符串先按年份排序,然后再按VT和HT排序。 (这意味着此特定情况下的输入已经排序)。
然而,执行停滞不前,所以我在比较函数中设置了一个计数器,如
public class PeriodComparer: IComparer<string>
{
int num = 0;
public int Compare(string x, string y)
{
if (++num >= 100000)
{
// setting a breakpoint here
}
var year1 = int.Parse(x.Substring(2));
var year2 = int.Parse(y.Substring(2));
if (year1 < year2)
return -1;
if (year1 > year2)
return 1;
var season1 = x.Substring(0, 2);
return season1 == "VT" ? -1 : 1;
}
}
断点被击中,因此至少需要进行100000次比较。
答案 0 :(得分:2)
如果您将一个调试语句添加到比较器并仅在两个字符串上调用它,您可以看到发生了什么。
你得到这个输出:
Comparing VT2010 to VT2010
Comparing VT2010 to HT2010
Comparing VT2010 to VT2010
一遍又一遍地重复。显然它无法弄清VT2010
在结果中应该去哪里,因为每次它认为它找到了正确的位置并进行了最后的比较,结果证明它离右边太远了,因为仍然{{1} }。
请注意,可以为两个相同的项目调用比较器。
如果添加行
VT2010 < VT2010
在比较方法的顶部,排序算法将能够找出if(x == y) { return 0; }
与VT2010
和VT2010
相比的正确相对顺序。
答案 1 :(得分:2)
你的季节比较可能需要一些调整。类似的东西:
public class PeriodComparer : IComparer<string>
{
int num = 0;
public int Compare(string x, string y)
{
if (++num >= 100000)
{
Console.WriteLine(num);
}
var year1 = int.Parse(x.Substring(2));
var year2 = int.Parse(y.Substring(2));
if (year1 < year2)
return -1;
if (year1 > year2)
return 1;
var season1 = x.Substring(0, 2);
var season2 = y.Substring(0, 2);
if (season1 == "VT" && season2 != "VT")
return -1;
if (season2 == "VT" && season1 != "VT")
return 1;
return StringComparer.InvariantCulture.Compare(season1, season2);
}
}
这将确保排序结果一致。
要进行比较,请使用“HJ2014”和“HT2014”的输入调用现有代码。它将返回1.现在用“HT2014”和“HJ2014”调用它 - 现在它将仍然返回1.这是意料之外的。
你基本上已经说过了:
“HJ2014”大于“HT2014”
和强>
“HJ2014”小于“HT2014”
显然,这两者都不可能是真的。因此,这会“混淆”排序算法,并使其旋转。
同样,您的代码也会声明:
“VT2014”小于“VT2014”
这显然是假的。这导致问题,因为OrderBy
使用了QuickSort,因此可以将条目与自身进行比较。
答案 2 :(得分:2)
比较任意项目时,请说A
和B
,我们必须确保
A == A
...
whenever A > B then B < A
请注意,在您的情况下,这些规则已损坏;此外,从不威胁字符串相等;简单的例子
var A = "VT2018";
// Expected 0, Actual -1
int result = (new PeriodComparer()).Compare(A, A);
正确准确(在处理public
类时,我们必须预期任何输入)实现:
public int Compare(string x, string y) {
// Special cases: equal strings, nulls
if (string.Equals(x, y))
return 0;
else if (string.Equals(null, x)) // null is smaller than any string
return -1;
else if (string.Equals(null, y))
return 1;
// Suffixes
// TrimStart('0'): we want "0003" == "3" < "10":
string suffixX = x.Length <= 2 ? "" : x.Substring(2).TrimStart('0');
string suffixY = y.Length <= 2 ? "" : y.Substring(2).TrimStart('0');
// Natural order: Length first (2000 > 900)...
if (suffixX.Length > suffixY.Length)
return 1;
else if (suffixX.Length < suffixY.Length)
return -1;
// ...Lexicograhical next: 2040 > 2030
int result = string.Compare(suffixX, suffixY);
if (result != 0)
return result;
// Equal Suffixes; compare prefixes
string prefixX = x.Length <= 2 ? x : x.Substring(0, 2);
string prefixY = y.Length <= 2 ? y : y.Substring(0, 2);
if (prefixX == "VT" && prefixY != "VT")
return -1;
else if (prefixY == "VT" && prefixX != "VT")
return 1;
return string.Compare(prefixX, prefixY);
}
答案 3 :(得分:0)
你不适应'tie-breaker'比较(子串“VT”与“HT”)相同的情况。