1

我有一种情况,我的所有列表成员都具有相同的 ID(ID 是字符串而不是整数)。作为业务规则的一部分,我需要按升序对列表进行排序。我的原始实现与下面非常相似。我希望在应用排序后得到不变的列表,因为所有列表成员都具有相同的 ID,但令我惊讶的是结果不同。

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

Id:D1.2 名称:Pachycephalosaurus
Id:D1.2 名称:Amargasaurus
Id:D1.2 名称:Mamenchisaurus
Id:D1.2 名称:恐爪龙
Id:D1.2 名称:腔骨龙
Id:D1.2 名称:偷蛋龙
Id: D1.2 名称:暴龙

使用备用比较器排序:

Id:D1.2 名称:Pachycephalosaurus
Id:D1.2 名称:偷蛋龙
Id:D1.2 名称:腔骨龙
Id:D1.2 名称:恐爪龙
Id:D1.2 名称:Mamenchisaurus
Id:D1.2 名称:Amargasaurus
Id: 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; }
}
4

7 回答 7

1

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

return string.Compare(x, y);

这使比较更“安全”,您不必检查空值。

或者,一个简单的 LINQ 语句将完成这项工作:

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

您还应该注意,一旦您在列表中获得一些项目,按 ID 作为字符串排序将导致错误的结果;21会放在前面3。您可能需要考虑int在某个阶段将其转换为 a。

于 2011-09-29T07:52:28.960 回答
1

您违反了IComparersince 的隐含合同,Compare(dino1,dino2)并且Compare(dino2,dino1)将返回dino1大于dino2dino2大于dino1。由于您没有正确定义订单,因此结果充其量往往是“随机的”。

如果您不能纯粹基于ID值定义总顺序,那么仅使用这些ID值就不能成为您IComparer实施的基础。

于 2011-09-29T07:47:47.700 回答
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...
}
于 2011-09-29T07:48:32.127 回答
1

您应该只return x.CompareTo(y);从您的private int Compare(string x, string y)方法返回,因为您只基于字符串进行比较......

像这样:

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

希望它有帮助,伊万

于 2011-09-29T07:41:19.260 回答
1

来自MSDN

此方法使用 Array.Sort,它使用 QuickSort 算法。这个实现执行了一个不稳定的排序;也就是说,如果两个元素相等,则可能不会保留它们的顺序。相反,稳定排序保留了相等元素的顺序。

(我的重点)

这正是你所看到的。

编辑 正如其他人所暗示的,您可以使用 linq 方法OrderBy,它确实执行稳定的排序:

var d2 = dinosaurs.OrderBy(d => d.Id).ToList();
于 2011-09-29T07:50:25.310 回答
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;
    }
}
于 2011-09-30T00:33:51.167 回答
0

可悲的是,据我所知,框架中没有实现稳定的排序方法。你必须自己做。

这个 http://www.csharp411.com/c-stable-sort/ 是稳定排序方法的一个很好的例子。

于 2011-09-29T08:41:53.507 回答