你如何按价值排序字典?

Kalid 731 .net c# sorting dictionary

我经常需要按值排序字典,包括键和值.例如,我有一个单词的散列和各自的频率,我想按频率排序.

有一个SortedList对单个值(比如频率)有好处,我想将它映射回单词.

SortedDictionary按键排序,而不是值.有些人诉诸于自定义课程,但是有更清洁的方法吗?

caryden.. 496

使用LINQ:

Dictionary<string, int> myDict = new Dictionary<string, int>();
myDict.Add("one", 1);
myDict.Add("four", 4);
myDict.Add("two", 2);
myDict.Add("three", 3);

var sortedDict = from entry in myDict orderby entry.Value ascending select entry;

这也可以提供很大的灵活性,你可以选择前10个,20个10%等.或者如果你使用你的单词频率索引type-ahead,你也可以包括StartsWith条款.

  • 我不确定它是否总是有效,因为迭代字典并不能保证KeyValuePairs按照它们插入的相同顺序被"拉".如果你在LINQ中使用orderby并不重要,因为Dictionary可以改变插入元素的顺序.它通常按预期工作,但没有保证,特别是对于大型词典. (18认同)
  • 返回类型应为`IEnumerable <KeyValuePair <TKey,TValue >>`或`OrderedDictionary <TKey,TValue>`.或者从一开始就应该使用`SortedDictionary`.对于一个简单的`Dictionary',MSDN明确指出"返回项目的顺序是未定义的".似乎@ rythos42的最新编辑应该受到指责.:) (15认同)
  • 请忽略`.ToDictionary`的所有建议 - [标准词典不保证排序顺序](http://stackoverflow.com/a/4007787/1860652) (14认同)
  • 如何将sortedDict更改回Dictionary <string,int>?在这里发布新的SO问题:http://stackoverflow.com/questions/3066182/c-convert-an-iorderedenumerablekeyvaluepairstring-int-into-a-dictionarystr (13认同)

Leon Bambric.. 491

使用:

using System.Linq.Enumerable;
...
List<KeyValuePair<string, string>> myList = aDictionary.ToList();

myList.Sort(
    delegate(KeyValuePair<string, string> pair1,
    KeyValuePair<string, string> pair2)
    {
        return pair1.Value.CompareTo(pair2.Value);
    }
);

由于您的目标是.NET 2.0或更高版本,因此您可以将其简化为lambda语法 - 它等效,但更短.如果您的目标是.NET 2.0,那么只有在使用Visual Studio 2008(或更高版本)的编译器时才能使用此语法.

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));

  • 它是一个班轮 - 你不需要大括号.它可以被重写为`myList.Sort((x,y)=> x.Value.CompareTo(y.Value));` (105认同)
  • 我使用了这个解决方案(谢谢!)但是我被困了一分钟,直到我读到Michael Stum的帖子(以及他来自John Timney的代码片段)并意识到myList是一个辅助对象,一个KeyValuePairs列表,它是从字典创建的,然后排序. (23认同)
  • 要对降序进行排序,请在比较中切换x和y:myList.Sort((x,y)=> y.Value.CompareTo(x.Value)); (19认同)
  • 我认为值得注意的是,这需要Linq用于ToList扩展方法. (4认同)
  • 你们有点过于复杂 - 一本字典已经实现了`IEnumerable`,所以你可以得到一个这样的排序列表:`var mySortedList = myDictionary.OrderBy(d => d.Value).ToList();` (3认同)
  • 抱歉,这个答案很难理解,因为我不熟悉委托关键字(可能在vb中有所不同),n目前还不清楚排序的位置,因为你需要运行项目数量乘以项目数量(没有项目平方)比较通过搜索/比较每个元素与每个元素的整个字典,或者如果你只是比较当前的n,那么你需要在集合的多个循环中做到这一点,这就是为什么我没有"得到它"的原因.也许有关排序和重新排序的位置的更多信息会有所帮助! (2认同)

sean.. 201

var ordered = dict.OrderBy(x => x.Value);

  • 这是一个很好的解决方案,但它应该在结束分号之前正确:.ToDictionary(pair => pair.Key,pair => pair.Value); (23认同)
  • @theJerm:[不是](http://stackoverflow.com/a/4007787/1860652) (12认同)
  • 不应该对字典进行强制转换,因为字典不是有序的.无法保证KeyValuePairs将保持您想要的顺序. (8认同)
  • 我不确定为什么这个解决方案不再流行 - 也许是因为它需要.NET 3.5? (5认同)
  • @theJerm通过将已排序的项目放回字典是保证的顺序呢?它今天可能有效,但不能保证. (2认同)

Kalid.. 157

环顾四周,并使用一些C#3.0功能,我们可以这样做:

foreach (KeyValuePair<string,int> item in keywordCounts.OrderBy(key=> key.Value))
{ 
    // do something with item.Key and item.Value
}

这是我见过的最干净的方式,类似于Ruby处理哈希的方式.

  • @AndriusNaruševičius:如果您将结果项目添加回字典中,您将销毁订单,因为[不保证以任何特定方式订购字典](http://stackoverflow.com/a/4007787/1430156). (5认同)
  • 使用此语法时,请不要忘记添加System.Linq命名空间. (4认同)
  • `(对于KeyValuePair <string,int> item in keywordCounts.OrderBy(key => key.Value)select item).ToDictionary(t => t.Key,t => t.Value)` - 只是你的一小部分回答:)谢谢,顺便说一句:) (4认同)

Matt Frear.. 147

您可以按值对字典进行排序并将其保存回自身(这样当您对其进行操作时,值将按顺序排出):

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

当然,它可能不正确,但它的工作原理.

  • 不正确:http://stackoverflow.com/a/4007787/1860652 (15认同)
  • 这种"工作"并不能保证.它是一个实现细节.它不需要在其他时间工作.错误的回答,downvoted. (13认同)
  • 如果要排序到降序列表,也可以使用OrderByDescending. (7认同)
  • 我很担心在生产代码中看到这一点.它不保证,可以随时更改.并不是说我回避实用的解决方案,它只是表明对数据结构的理解不足. (3认同)
  • 字典输出不保证具有任何特定的排序顺序. (2认同)

Michael Stum.. 59

在较高的层次上,您没有其他选择可以遍历整个词典并查看每个值.

也许这会 有所帮助:http: //bytes.com/forum/thread563638.html从John Timney复制/粘贴:

Dictionary<string, string> s = new Dictionary<string, string>();
s.Add("1", "a Item");
s.Add("2", "c Item");
s.Add("3", "b Item");

List<KeyValuePair<string, string>> myList = new List<KeyValuePair<string, string>>(s);
myList.Sort(
    delegate(KeyValuePair<string, string> firstPair,
    KeyValuePair<string, string> nextPair)
    {
        return firstPair.Value.CompareTo(nextPair.Value);
    }
);

  • stringnextPair - > string> nextPair stringfirstPair - > string> firstPair (3认同)

Roger Willco.. 23

无论如何,你永远无法对字典进行排序.他们实际上没有订购.字典的保证是键和值集合是可迭代的,并且可以通过索引或键检索值,但这里不保证任何特定的顺序.因此,您需要将名称值对添加到列表中.

  • 这是答案,因为词典不可排序.它散列键,您可以对其执行极快的搜索操作. (3认同)

Zar Shardan.. 16

您不对字典中的条目进行排序..NET中的字典类是作为哈希表实现的 - 根据定义,此数据结构不可排序.

如果您需要能够迭代您的集合(按键) - 您需要使用SortedDictionary,它实现为二进制搜索树.

在您的情况下,源结构是无关紧要的,因为它按不同的字段排序.您仍然需要按频率对其进行排序,并将其放入按相关字段(频率)排序的新集合中.所以在这个集合中,频率是键,单词是值.由于许多单词可以具有相同的频率(并且您将其用作键),因此您既不能使用Dictionary也不能使用SortedDictionary(它们需要唯一键).这将为您提供SortedList.

我不明白为什么你坚持维护主/第一本词典中原始项目的链接.

如果集合中的对象具有更复杂的结构(更多字段),并且您需要能够使用几个不同的字段作为键来有效地访问/排序它们 - 您可能需要一个自定义数据结构,该结构将由主存储组成支持O(1)插入和删除(LinkedList)和几个索引结构--Dictionaries/SortedDictionaries/SortedLists.这些索引将使用复杂类中的一个字段作为键,并将LinkedList中LinkedListNode的指针/引用用作值.

您需要协调插入和删除以使索引与主集合(LinkedList)保持同步,并且删除将是相当昂贵的我认为.这与数据库索引的工作方式类似 - 它们非常适合查找,但当您需要执行许多限制和删除时,它们会成为负担.

如果您要进行一些查找重处理,上述所有内容都是合理的.如果您只需要按频率排序就输出它们,那么您只需生成一个(匿名)元组列表:

var dict = new SortedDictionary<string, int>();
// ToDo: populate dict

var output = dict.OrderBy(e => e.Value).Select(e => new {frequency = e.Value, word = e.Key}).ToList();

foreach (var entry in output)
{
    Console.WriteLine("frequency:{0}, word: {1}",entry.frequency,entry.word);
}


mrfazolka.. 13

Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);

  • 也不正确.请参见此处:http://stackoverflow.com/a/4007787/463828 (2认同)

mythz.. 10

或者为了好玩,你可以使用一些LINQ扩展优点:

var dictionary = new Dictionary<string, int> { { "c", 3 }, { "a", 1 }, { "b", 2 } };
dictionary.OrderBy(x => x.Value)
  .ForEach(x => Console.WriteLine("{0}={1}", x.Key,x.Value));


lasitha edir.. 10

排序值

这显示了如何对Dictionary中的值进行排序.我们看到一个可以在Visual Studio中编译并运行的控制台程序.它为Dictionary添加了键,然后按其值对它们进行排序.请记住,Dictionary实例最初不以任何方式排序.我们在查询语句中使用LINQ orderby关键字.

对字典[C#]进行排序的OrderBy子句程序

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // Example dictionary.
        var dictionary = new Dictionary<string, int>(5);
        dictionary.Add("cat", 1);
        dictionary.Add("dog", 0);
        dictionary.Add("mouse", 5);
        dictionary.Add("eel", 3);
        dictionary.Add("programmer", 2);

        // Order by values.
        // ... Use LINQ to specify sorting by value.
        var items = from pair in dictionary
                orderby pair.Value ascending
                select pair;

        // Display results.
        foreach (KeyValuePair<string, int> pair in items)
        {
            Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
        }

        // Reverse sort.
        // ... Can be looped over in the same way as above.
        items = from pair in dictionary
        orderby pair.Value descending
        select pair;
    }
}

产量

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5


BSalita.. 9

使用VB.NET 对SortedDictionary列表进行排序以绑定到ListView控件中:

Dim MyDictionary As SortedDictionary(Of String, MyDictionaryEntry)

MyDictionaryListView.ItemsSource = MyDictionary.Values.OrderByDescending(Function(entry) entry.MyValue)

Public Class MyDictionaryEntry ' Need Property for GridViewColumn DisplayMemberBinding
    Public Property MyString As String
    Public Property MyValue As Integer
End Class

XAML:

<ListView Name="MyDictionaryListView">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding Path=MyString}" Header="MyStringColumnName"></GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding Path=MyValue}" Header="MyValueColumnName"></GridViewColumn>
         </GridView>
    </ListView.View>
</ListView>


用户甲.. 5

获取已排序字典的最简单方法是使用内置SortedDictionary类:

//Sorts sections according to the key value stored on "sections" unsorted dictionary, which is passed as a constructor argument
System.Collections.Generic.SortedDictionary<int, string> sortedSections = null;
if (sections != null)
{
    sortedSections = new SortedDictionary<int, string>(sections);
}

sortedSections 将包含排序版本 sections

  • 正如你在评论中提到的那样,`SortedDictionary`按键排序.OP希望按值排序.在这种情况下,`SortedDictionary`没有帮助. (5认同)
  • @mbrownnyc - nope,这样做需要VALUES唯一的假设或前提条件,这是不能保证的. (2认同)

Qwertie.. 5

如果您想要的是具有按值排序的"临时"列表,则其他答案都很好.但是,如果你想拥有排序字典来Key自动同步与被排序另一个字典Value,你可以使用Bijection<K1, K2>.

Bijection<K1, K2> 允许您使用两个现有字典初始化集合,因此如果您希望其中一个字典未排序,并且您希望对另一个字典进行排序,则可以使用以下代码创建您的双射

var dict = new Bijection<Key, Value>(new Dictionary<Key,Value>(), 
                               new SortedDictionary<Value,Key>());

您可以使用dict任何普通字典(它实现IDictionary<K, V>),然后调用dict.Inverse以获取排序依据的"逆"字典Value.

Bijection<K1, K2>Loyc.Collections.dll的一部分,但如果你愿意,你可以简单地将源代码复制到你自己的项目中.

注意:如果有多个键具有相同的值,则无法使用Bijection,但您可以手动在普通Dictionary<Key,Value>和a 之间进行同步BMultiMap<Value,Key>.