我的情况是我的所有列表成员都有相同的ID(Id是字符串而不是整数)。作为业务规则的一部分,我需要按升序对列表进行排序。我原来的实现与下面非常类似。我希望在应用排序后保持列表不变,因为所有列表成员都有相同的ID,但令我惊讶的是结果不同。
以下是排序前的原始列表。
Id:D1.2名称:Pachycephalosaurus
Id:D1.2名称:Amargasaurus
Id:D1.2名称:Mamenchisaurus
Id:D1.2名称:Deinonychus
Id:D1.2名称:Coelophysis
Id:D1.2名称:Oviraptor
Id:D1.2名称:Tyrannosaur
使用备用比较器排序:
Id:D1.2名称:Pachycephalosaurus
Id:D1.2名称:Oviraptor
Id:D1.2名称:Coelophysis
Id:D1.2名称:Deinonychus
Id:D1.2名称:Mamenchisaurus
Id:D1.2名称:Amargasaurus
Id:D1.2名称:Tyrannosaur
代码
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 :(得分:1)
您应该仅从return x.CompareTo(y);
方法返回private int Compare(string x, string y)
,因为您只是根据字符串进行比较...
像这样:
private int Compare(string x, string y)
{
return x.CompareTo(y);
}
希望它有所帮助, 伊万
答案 1 :(得分:1)
您违反了隐含的IComparer
合同,Compare(dino1,dino2)
和Compare(dino2,dino1)
将返回dino1
大于dino2
和dino2
}大于dino1
。由于您没有正确定义订单,因此结果往往是“随机”的。
如果您无法仅根据ID
值定义总订单,那么仅使用ID
值不能成为IComparer
实施的基础。
答案 2 :(得分:1)
你违反了IComparable
的合同;当你的ID相等时,你实际上是说一个比另一个大(所以需要排序)
小于零此对象小于其他参数。 零此对象与其他对象相同。 大于零此对象比其他对象大。
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...
}
答案 3 :(得分:1)
来自MSDN:
此方法使用Array.Sort,它使用QuickSort算法。这个 实施执行不稳定排序;也就是说,如果有两个元素 相同,他们的订单可能不被保留。相比之下,稳定的排序 保留相等元素的顺序。
(我的重点)
这正是你所看到的。
修改强> 正如其他人所暗示的,你可以使用linq方法OrderBy,它确实执行稳定的排序:
var d2 = dinosaurs.OrderBy(d => d.Id).ToList();
答案 4 :(得分:1)
我个人会使用icesar的答案,但改为使用静态string.Compare方法:
return string.Compare(x, y);
这使得比较有点“更安全”,您不必检查空值。
或者,一个简单的LINQ语句可以完成这项工作:
myList = myList.OrderBy(p => p.ID).ThenBy(p => p.Name);
您还应该注意,一旦您在列表中获得了一些项目,按ID排序为字符串将导致错误的结果; 21
将放在3
之前。您可能需要考虑在某个阶段将其投放到int
。
答案 5 :(得分:0)
遗憾的是,据我所知,Frameworks中没有实现稳定的排序方法。你必须自己做。
此 http://www.csharp411.com/c-stable-sort/ 是稳定排序方法的一个很好的例子。
答案 6 :(得分: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;
}
}