2011-09-29 43 views
1

我有一种情况,即所有列表成员都具有相同的ID(Id是字符串而不是整数)。作为业务规则的一部分,我需要按升序对列表进行排序。我原来的实现与下面非常类似。由于所有列表成员都有相同的ID,我希望在应用排序后得到不变的列表,但令我惊讶的是结果不同。C#IComparer在比较相同字符串时返回意外结果

以下是我在排序前的原始列表。

编号:D1.2名称:厚头龙
编号:D1.2名称:阿马加龙属
编号:D1.2名称:马门溪龙
编号:D1.2名称:恐爪龙
编号:D1.2名称:腔骨龙
编号:D1.2名称:偷蛋龙
编号:D1.2名称:霸王龙

排序交替比较器:

编号:D1.2娜我:厚头龙
编号:D1.2名称:偷蛋龙
编号:D1.2名称:腔骨龙
编号:D1.2名称:恐爪龙
编号:D1.2名称:马门溪龙
编号:D1.2名称:阿马加龙属
编号:D1.2名称:霸王龙

代码

class Program 
{ 
    static void Main(string[] args) 
    { 
     new ComparerIssue().MainMethod(); 
     Console.ReadKey(); 
    } 
} 

internal class DinoComparer : IComparer<Dinosaur> 
{ 
    public int Compare(Dinosaur dinosaur1, Dinosaur dinosaur2) 
    { 
     return Compare(dinosaur1.Id, dinosaur2.Id); 
    } 

    private int Compare(string x, string y) 
    { 
     if (x == y) 
     { 
      return 1; //I have tried using 1 and 0; -1 throws exception 
     } 
     return x.CompareTo(y); 
    } 
} 
public class ComparerIssue 
{ 
    public void MainMethod() 
    { 
     List<Dinosaur> dinosaurs = new List<Dinosaur>(); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Pachycephalosaurus" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Amargasaurus" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Mamenchisaurus" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Deinonychus" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Coelophysis" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Oviraptor" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Tyrannosaur" }); 
     Display(dinosaurs); 

     DinoComparer dc = new DinoComparer(); 

     Console.WriteLine("\nSort with alternate comparer:"); 

     dinosaurs.Sort(dc); 
     Display(dinosaurs); 
    } 
    private static void Display(IEnumerable<Dinosaur> list) 
    { 
     Console.WriteLine(); 
     foreach (Dinosaur dinosaur in list) 
     { 
      Console.WriteLine("Id: " + dinosaur.Id + " Name: " + dinosaur.Name); 
     } 
    } 
} 
public class Dinosaur 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 
+0

'if(x == y)'实际上会比较两个字符串,而不是它们的引用。比较他们的引用使用'object.ReferenceEquals'。 –

回答

1

你应该回复O从private int Compare(string x, string y)方法NLY return x.CompareTo(y);,因为你是比较只是基于字符串...

像这样:

private int Compare(string x, string y) 
{ 
    return x.CompareTo(y); 
} 

希望它能帮助, 伊万

+0

嗨伊万,感谢您的及时回复。我想尝试返回0或1,看看是否有任何区别,因为两个字符串值是相等的。
无论如何,我已经尝试了你刚刚提出的建议,但仍然没有得到原始列表。 –

1

您违反的隐含契约IComparer因为Compare(dino1,dino2)Compare(dino2,dino1)将返回dino1大于dino2dino2大于dino1。由于您没有正确定义订单,因此结果往往会是“随机的”。

如果您无法单纯根据ID值定义总订单,那么仅使用ID值不能作为您的IComparer实施的基础。

1

您违反了IComparable的合同;当你的ID是平等的,你实际上是在说一个大于其他的(所以需要进行排序)

documentation:小于零

此对象是小于其他参数。 零此对象等于其他。 大于零此对象大于其他。

的另一种实现你的Compare是:

private int Compare(string x, string y) 
{ 
    return x.CompareTo(y); 
    // There would be potential to do secondary sorts if the line above only returned zero - you'd obviously need to capture and test the result... 
} 
+0

+1:但希望看到这种处理情况,其中'x == null' –

1

MSDN

这种方法使用的Array.Sort,它使用了快速排序算法。这个 执行执行不稳定排序;也就是说,如果两个元素是 相等,他们的顺序可能会保留而不是。相反,稳定的分类 保留了相同元素的顺序。

(我的重点)

而这正是你所看到的情况发生。

编辑 作为暗示别人,你可以使用LINQ方法OrderBy,它不执行稳定的排序:

var d2 = dinosaurs.OrderBy(d => d.Id).ToList(); 
+0

嗨汉斯,感谢您的及时回复,你能告诉我(点我)稳定排序的例子吗?有没有办法在泛型List中实现稳定的排序?像写扩展自定义排序方法? –

1

个人而言,我会用从icesar答案,但使用静态string.Compare方法相反:

return string.Compare(x, y); 

这使得比较有点“安全”,你不必检查空值。

或者一个简单的LINQ语句将做的工作:

myList = myList.OrderBy(p => p.ID).ThenBy(p => p.Name); 

你还应该注意,通过ID排序为字符串将导致错误的结果,一旦你在列表中的几个项目; 21将放置在3之前。你可能想考虑在某个阶段将它投射到int

0

我衷心感谢大家的反馈意见。我已使用插入方法在http://www.csharp411.com/c-stable-sort/上实施了稳定排序。我包括最终的参考代码。

internal class DinoComparer : IComparer<Dinosaur> 
{ 
    public int Compare(Dinosaur dinosaur1, Dinosaur dinosaur2) 
    { 
     return Compare(dinosaur1.Id, dinosaur2.Id); 
    } 

    private int Compare(string x, string y) 
    { 
     return x.CompareTo(y); 
    } 
} 
public class ComparerIssue 
{ 
    public void MainMethod() 
    { 
     List<Dinosaur> dinosaurs = new List<Dinosaur>(); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Pachycephalosaurus" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Amargasaurus" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Mamenchisaurus" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Deinonychus" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Coelophysis" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Oviraptor" }); 
     dinosaurs.Add(new Dinosaur() { Id = "D1.2", Name = "Tyrannosaur" }); 
     Display(dinosaurs); 

     //Console.WriteLine("\nSort with unstable comparer:"); 
     //dinosaurs.Sort(new DinoComparer()); 

     Console.WriteLine("\nSort with stable comparer:"); 
     dinosaurs = (List<Dinosaur>)InsertionSort.Sort(dinosaurs, new DinoComparer().Compare); 

     Display(dinosaurs); 
    } 
    private static void Display(IEnumerable<Dinosaur> list) 
    { 
     Console.WriteLine(); 
     foreach (Dinosaur dinosaur in list) 
     { 
      Console.WriteLine("Id: " + dinosaur.Id + " Name: " + dinosaur.Name); 
     } 
    } 
} 
public class Dinosaur 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 
public class InsertionSort 
{ 
    public static IList<T> Sort<T>(IList<T> list, Comparison<T> comparison) 
    { 
     if (list == null) 
      throw new ArgumentNullException("list"); 
     if (comparison == null) 
      throw new ArgumentNullException("comparison"); 

     int count = list.Count; 
     for (int j = 1; j < count; j++) 
     { 
      T key = list[j]; 

      int i = j - 1; 
      for (; i >= 0 && comparison(list[i], key) > 0; i--) 
      { 
       list[i + 1] = list[i]; 
      } 
      list[i + 1] = key; 
     } 
     return list; 
    } 
} 
相关问题