【问题标题】:Sorting a Dictionary in place with respect to keys根据键对字典进行就地排序
【发布时间】:2011-02-11 22:23:24
【问题描述】:

我有一本像 C# 一样的字典

Dictionary<Person, int>

并且我想根据键(Person 类中的一个字段)对字典就地进行排序。我该怎么做?互联网上的每个可用帮助都是列表的帮助,没有就地排序字典的特定示例。任何帮助将不胜感激!

【问题讨论】:

  • 我不确定我是否理解您的问题,因为字典没有按任何顺序列举?您可以遍历键或值,您可以轻松地对它们进行动态排序...
  • 这不可能是你真正想要的。数组可以原地排序,因为数组排序的结果就是数组。但是 Dictionary 不是一个数组,因此它不能被其条目排序的结果所取代。对条目进行排序并将结果保存在数组或列表中。并且接受的答案可能不是您想要的......从 SortedList 或 SortedDictionary 输入和访问条目比从 Dictionary 慢得多。

标签: c# sorting dictionary


【解决方案1】:

您无法对 Dictionary&lt;TKey, TValue&gt; 进行排序 - 它本质上是无序的。 (或者更确切地说,检索条目的顺序是特定于实现的。您不应该依赖它在版本之间以相同的方式工作,因为排序不是其设计功能的一部分。)

可以使用SortedList&lt;TKey, TValue&gt;SortedDictionary&lt;TKey, TValue&gt;,两者都按键排序(以可配置的方式,如果您将IEqualityComparer&lt;T&gt; 传递给构造函数)- 可能是对你有用吗?

很少注意名称SortedList 中的“列表”一词——它仍然是一个字典,因为它将键映射到值。它实现在内部有效地使用列表 - 因此它不是通过哈希码查找,而是进行二进制搜索。 SortedDictionary 类似地基于二分搜索,但通过树而不是列表。

【讨论】:

  • 小心使用SortedList&lt;K,V&gt;,但是:如果你建立一个大列表(假设项目没有预先排序),它会很慢。通常您应该改用SortedDictionary&lt;K,V&gt;,或者使用第三方BDictionary&lt;K,V&gt; 以获得类似于SortedDictionary 的性能,而不会失去通过索引或“查找最近的键”访问项目的能力。
  • 二进制搜索而不是在排序键旁边维护哈希有什么优势?如果我不是几乎只进行有序枚举,为什么还要关心元素是否有序? 如果我更关心单个元素查找,但其次想根据键顺序进行枚举,我是否会坚持管理单独的键列表 Steve's answer 如果这是我想要的用途,SortedList & SortedDictionary 实际上是错误工具,对吧?也就是说,如果我真的只想对字典 keys 进行排序呢?
  • @ruffin:优点是避免了复杂性。是的,据我所知,没有内置的“排序和散列”集合。请注意,这样的集合更难使用 以及构建 - 必须同时提供相等比较和哈希码函数以及排序函数。当然,同时保存这两个集合也会产生内存成本。您需要衡量实际数据的二进制搜索与哈希查找的成本 - 您可能会发现它实际上并不重要,除非您的集合非常庞大。
  • @ruffin “二进制搜索而不是在排序键旁边维护哈希有什么优势?” -- 哈希表的内存和添加或删除条目时维护它的时间。 “我为什么要关心元素是有序的”——如果你不关心元素是有序的,那么只需使用字典(我通常会推荐使用 SortedList 或 SortedDictionary)“但其次要根据键顺序进行枚举" -- 偶尔需要枚举的 KeyValuePairs 时,对它们进行排序很简单:dict.OrderBy(kv => kv.Key)
  • @ruffin “如果我真的只想对字典键进行排序怎么办?” - 没有这样的事情 - 这是一个类别错误。数组可以就地排序......不是数组的东西都可以。 (嗯,除了带有可变节点的链表,但是就地排序这样的东西会很疯狂而且非常昂贵。)当然你可以做类似var array = dict.Keys.ToArray(); array.Sort();
【解决方案2】:

尝试使用SortedDictionary

【讨论】:

  • 您的回答比God 慢了 21 秒。那还不错。
【解决方案3】:

正确答案已经说明(只需使用 SortedDictionary)。

但是,如果您偶然需要将您的集合保留为字典,则可以按顺序访问字典键,例如,通过对列表中的键进行排序,然后使用此列表来访问词典。一个例子……

Dictionary<string, int> dupcheck = new Dictionary<string, int>();

...一些填写“dupcheck”的代码,然后...

if (dupcheck.Count > 0) {
  Console.WriteLine("\ndupcheck (count: {0})\n----", dupcheck.Count);
  var keys_sorted = dupcheck.Keys.ToList();
    keys_sorted.Sort();
  foreach (var k in keys_sorted) {
    Console.WriteLine("{0} = {1}", k, dupcheck[k]);
  }
}

不要忘记using System.Linq;

【讨论】:

  • “如果偶然你需要将你的集合保留为字典”——保留它的明显原因是它的插入、删除和查找速度要快得多。至于var keys_sorted = dupcheck.Keys.ToList(); keys_sorted.Sort();——更简单的是keys_sorted = dupcheck.Keys.OrderBy(k =&gt; k).ToList(); ...如果您要使用这些值,那么只需foreach (var ent in dupcheck.OrderBy(kv =&gt; kv.Key)) Console.WriteLine($"{ent.Key} = {ent.Value}");
  • 这不是字典对象的排序,这只是显示的排序,是一种解决方法:(
【解决方案4】:

由于这个答案的高搜索排名,我认为 LINQ OrderBy 解决方案值得展示:

class Person
{
    public Person(string firstname, string lastname)
    {
        FirstName = firstname;
        LastName = lastname;
    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

static void Main(string[] args)
{
    Dictionary<Person, int> People = new Dictionary<Person, int>();

    People.Add(new Person("John", "Doe"), 1);
    People.Add(new Person("Mary", "Poe"), 2);
    People.Add(new Person("Richard", "Roe"), 3);
    People.Add(new Person("Anne", "Roe"), 4);
    People.Add(new Person("Mark", "Moe"), 5);
    People.Add(new Person("Larry", "Loe"), 6);
    People.Add(new Person("Jane", "Doe"), 7);

    foreach (KeyValuePair<Person, int> person in People.OrderBy(i => i.Key.LastName))
    {
        Debug.WriteLine(person.Key.LastName + ", " + person.Key.FirstName + " - Id: " + person.Value.ToString());
    }
}

输出:

Doe, John - Id: 1
Doe, Jane - Id: 7
Loe, Larry - Id: 6
Moe, Mark - Id: 5
Poe, Mary - Id: 2
Roe, Richard - Id: 3
Roe, Anne - Id: 4

在此示例中,也可以将 ThenBy 用于名字:

foreach (KeyValuePair<Person, int> person in People.OrderBy(i => i.Key.LastName).ThenBy(i => i.Key.FirstName))

那么输出是:

Doe, Jane - Id: 7
Doe, John - Id: 1
Loe, Larry - Id: 6
Moe, Mark - Id: 5
Poe, Mary - Id: 2
Roe, Anne - Id: 4
Roe, Richard - Id: 3

LINQ 还为那些需要它的人提供了 OrderByDescendingThenByDescending

【讨论】:

    【解决方案5】:

    根据设计,字典是不可排序的。如果您需要字典中的此功能,请查看 SortedDictionary。

    【讨论】:

      【解决方案6】:

      看看SortedDictionary,甚至还有一个构造函数重载,因此您可以传入自己的 IComparable 进行比较。

      【讨论】:

        【解决方案7】:

        Dictionary 是作为哈希表实现的,而 SortedDictionary 是作为红黑树实现的。

        如果您没有利用算法中的顺序,只需要在输出前对数据进行排序,使用 SortedDictionary 会对性能产生负面影响

        您可以像这样“排序”字典:

        Dictionary<string, int> dictionary = new Dictionary<string, int>();
        // algorithm
        return new SortedDictionary<string, int>(dictionary);
        

        【讨论】:

        • 如果要按键排序,使用dictionary.OrderBy(kv =&gt; kv.Key)
        猜你喜欢
        • 2011-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-23
        • 1970-01-01
        • 2013-09-27
        • 2018-08-13
        相关资源
        最近更新 更多