【问题标题】:Dictionary Sort .NET 2.0 [closed]字典排序.NET 2.0 [关闭]
【发布时间】:2016-04-05 15:24:00
【问题描述】:

我在如何正确排序 .NET 2.0 中的字典时遇到问题。这段代码有点旧(2002 年或其他),它可以工作,但不是我想要的方式。由于 AvailableFlights 字典可能非常庞大,因此这种排序功能可能会花费大量时间,而客户没有这么多时间。

任何人都知道如何做到这一点,我知道的唯一方法是添加 orderby 或其他东西,因为 2002 年我在花园里玩耍。

注意:这是一个正在进行的网站的代码,问题是,我的老板想要这个更快,但我无法对项目进行重大更改。

排序函数本身是这样工作的:有一个字典 AvailableFlight,其中包含 Flight 对象(带有 TotalPrice)。这来自外部来源,因此预过滤不是一种选择。要实现的目标是将 TotalPrice 最低的航班排在首位

对于不知道我在问什么的人,在我的项目中有一个字典,其中包含存储为具有相应整数键的对象的飞行对象。 飞行对象有一个属性Totalprice,需要ASC进行排序。我提供的代码会出现这种情况,仅处理这段代码的时间大约需要 30 秒或更长时间,这是不可接受的。所以问题是,我该如何改进这一点,以减少处理时间。

 public void SortFlightResult()
    {
        //bool to check sorting is done or not
        bool blSort = true;
        //bool to stay in while or not
        bool blWhileSort = true;
        while (blWhileSort)
        {
            //check the availableFlights
            foreach (int i in AvailableFlights.Keys)
            {
                foreach (int j in AvailableFlights.Keys)
                {
                    //if id j is greater then id i and price is less then j must be in place of i
                    if ((AvailableFlights[j].TotalPrice < AvailableFlights[i].TotalPrice) && (j > i))
                    {
                        //set temperary AvailableFlight object
                        AvailableFlight avTemp = new AvailableFlight();
                        avTemp = AvailableFlights[i];
                        AvailableFlights[i] = AvailableFlights[j];
                        //keep id of the i (if j.id = 3 and i.id = 2) replace i with j but let id = 2
                        AvailableFlights[i].ID = i;
                        AvailableFlights[j] = avTemp;
                        AvailableFlights[j].ID = j;
                        //set bool fase so we know sort is not done
                        blSort = false;
                        //end both foreach loop so we can start over from the top of availableFlights
                        goto endLoop;
                    }
                }
            }
        endLoop:
            //if true --> availableFlights is sorted set bool while false to quit the function
            if (blSort)
            {
                blWhileSort = false;
            }
            else
            {//set bool sort back to true
                blSort = true;
            }
        }
    }

抛开所有的废话*t,感谢@D Stanley 的有用评论。 我将算法更改为 堆排序,处理排序的时间从大约 30 秒 减少到 400 毫秒,真的很高兴!

对堆排序代码感兴趣的人:

堆排序

    public void HeapSort()
    {
        Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();

        //Build Max-Heap
        Dictionary<int, AvailableFlight> input = AvailableFlights;
        int heapSize = input.Keys.Count;

        for (int p = (heapSize -1) /2; p >= 0; p--)
        {
            MaxHeapify(AvailableFlights, heapSize, p);
        }
        for (int i = AvailableFlights.Count - 1; i > 0; i--)
        {
            //Swap
            AvailableFlight temp = input[i];
            input[i] = input[0];
            input[0] = temp;

            heapSize--;
            MaxHeapify(AvailableFlights, heapSize, 0);
        }

        watch.Stop();
        Debug.WriteLine("SortFlightResult 2: " + watch.ElapsedMilliseconds);
    }

MaxHeapify

    private static void MaxHeapify(Dictionary<int, AvailableFlight> input, int heapSize, int index)
    {
        int left = (index + 1) * 2 - 1;
        int right = (index + 1) * 2;
        int largest = 0;

        if (left < heapSize && input[left].TotalPrice > input[index].TotalPrice)
        {
            largest = left;
        }
        else
        {
            largest = index;
        }

        if (right < heapSize && input[right].TotalPrice > input[largest].TotalPrice)
        {
            largest = right;
        }
        if (largest != index)
        {
            AvailableFlight temp = input[index];
            input[index] = input[largest];
            input[largest] = temp;

            MaxHeapify(input, heapSize, largest);
        }
    }

【问题讨论】:

  • 字典没有排序——如果你想要一个项目列表并且能够重新排序项目使用List而不是Dictionary
  • @Sinatr 即使使用已排序的字典,代码也会重新组织项目。没有迹象表明这里使用了字典的好处。
  • 您使用goto这一事实表明您没有使用正确的过程或数据结构。
  • 改变排序算法会被认为是“巨大的改变”吗?您可以对 sorting algorithms 进行一些研究,看看根据您的起始数据是什么不同的算法可能更快。

标签: c# .net sorting dictionary


【解决方案1】:

假设你有这样的AvailableFlight类:

public class AvailableFlight
{
    public decimal TotalPrice { get; set; }
    // ... more properties
}

您可以像这样创建一个实现IComparer&lt;AvailableFlight&gt; 的类:

public class FlightByPriceComparer : IComparer<AvailableFlight>
{
    public int Compare(AvailableFlight x, AvailableFlight y)
    {
        if (ReferenceEquals(x, null))
            return ReferenceEquals(y, null) ? 0 : -1;
        if (ReferenceEquals(y, null)) return 1;
        return x.TotalPrice.CompareTo(y.TotalPrice);
    }
}

并使用它对字典值的List&lt;AvailableFlight&gt; 进行排序:

Dictionary<int, AvailableFlight> AvailableFlights = ... // whereever you got them from
List<AvailableFlight> sortedFlights = new List<AvailableFlight>(AvailableFlights.Values);
sortedFlights.Sort(new FlightByPriceComparer());

这应该比冒泡排序更快,根据documentation 它使用这些排序算法:

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

平均来说,这个方法是一个O(n log n)的操作,其中n是Count;在最坏的情况下,它是一个 O(n ^ 2) 操作。


请注意,不可能按字典的值对字典进行排序,有一个 SortedDictionary,但它仅按其 Keys 排序。

【讨论】:

  • 如果它来自常规字典,则很可能无论如何都未排序。 QuickSort 几乎是您在不并行化所有内容的情况下获得的最快速度(这可能算作一个很大的变化) - 所以我认为这是解决问题的最佳答案。
【解决方案2】:

使用 System.Linq 让阅读变得简单明了:

AvailableFlights = AvailableFlights.OrderBy(x => x.Value.TotalPrice).ToDictionary(x => x.Key, x=>x.Value);

【讨论】:

  • LINQ 在 .NET2.0 中不可用,因此它甚至无法在 OP 的代码中编译。
  • uuups,没看先决条件,抱歉。所以只能选择 List 或 Array 排序!
猜你喜欢
  • 2018-01-02
  • 2020-05-26
  • 1970-01-01
  • 2018-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多