我经常需要根据值对字典(由键和值组成)进行排序。例如,我有一个单词和相应频率的散列,我想按频率排序。

有一个SortedList,它适用于单个值(比如频率),我想把它映射回单词。

SortedDictionary按键排序,而不是按值。有些人求助于自定义课程,但有没有更干净的方法呢?


环顾四周,使用一些c# 3.0特性,我们可以这样做:

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

这是我见过的最干净的方法,类似于Ruby处理散列的方法。


在较高的层次上,您别无选择,只能遍历整个Dictionary并查看每个值。

也许这有帮助: 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);
    }
);

Use:

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));

使用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%等等。或者,如果您正在使用词频索引进行提前输入,您还可以包括StartsWith子句。


反正你也不可能对字典进行排序。它们实际上并不是有序的。字典的保证是键和值集合是可迭代的,值可以通过索引或键检索,但不保证任何特定的顺序。因此,您需要将名称值对放入一个列表中。


获得一个排序字典最简单的方法是使用内置的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将包含section的排序版本


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

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>

或者为了好玩,你可以使用一些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));

你可以用:

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

你可以按值对Dictionary进行排序并将其保存回自身(这样当你对它进行foreach时,值就会按顺序出来):

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

当然,这可能不正确,但它是有效的。海鲁姆定律意味着这很可能会继续起作用。


你可以按值对Dictionary进行排序,并使用下面的代码在Dictionary中获取结果:

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          

您不需要对Dictionary中的条目进行排序。. net中的Dictionary类是作为哈希表实现的——这个数据结构在定义上是不可排序的。

如果你需要能够遍历你的集合(按键)-你需要使用SortedDictionary,它被实现为二叉搜索树。

然而,在您的例子中,源结构是不相关的,因为它是根据不同的字段排序的。您仍然需要按频率对其进行排序,并将其放入按相关字段(频率)排序的新集合中。在这个集合中,频率是键,单词是值。由于许多单词可以具有相同的频率(并且您将使用它作为键),因此不能既使用Dictionary也使用SortedDictionary(它们需要惟一的键)。这将留给您一个SortedList。

我不明白为什么你坚持在你的主/第一个字典中保持一个到原始条目的链接。

If the objects in your collection had a more complex structure (more fields) and you needed to be able to efficiently access/sort them using several different fields as keys - You would probably need a custom data structure that would consist of the main storage that supports O(1) insertion and removal (LinkedList) and several indexing structures - Dictionaries/SortedDictionaries/SortedLists. These indexes would use one of the fields from your complex class as a key and a pointer/reference to the LinkedListNode in the LinkedList as a value.

你需要协调插入和删除,以保持你的索引与主集合(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);
}

假设你有一个字典,你可以直接使用下面一行对它们进行排序:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);

假设我们有一个这样的字典:

Dictionary<int, int> dict = new Dictionary<int, int>();
dict.Add(21,1041);
dict.Add(213, 1021);
dict.Add(45, 1081);
dict.Add(54, 1091);
dict.Add(3425, 1061);
dict.Add(768, 1011);

你可以使用临时字典来存储值:

Dictionary<int, int> dctTemp = new Dictionary<int, int>();
foreach (KeyValuePair<int, int> pair in dict.OrderBy(key => key.Value))
{
    dctTemp.Add(pair.Key, pair.Value);
}

你可以用:

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

如果您想要的只是一个按值排序的“临时”列表,那么其他答案都很好。然而,如果你想让一个按Key排序的字典自动与另一个按Value排序的字典同步,你可以使用Bijection<K1, K2>类。

双射<K1, K2>允许您使用两个现有字典初始化集合,因此如果您希望其中一个字典是无序的,而另一个字典是有序的,您可以使用如下代码创建双射

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

您可以像使用任何普通字典一样使用dict(它实现了dicictionary <K, V>),然后调用dict。以获得“逆”字典,它是由值排序。

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

注意:如果有多个键具有相同的值,您不能使用双射,但您可以手动同步普通Dictionary<Key, value >和BMultiMap< value, Key>。


实际上在c#中,字典没有sort()方法。 如果你对按值排序更感兴趣, 在为值提供键之前,您无法获取值。 简而言之,你需要使用LINQ的OrderBy()迭代它们,

var items = new Dictionary<string, int>();
items.Add("cat", 0);
items.Add("dog", 20);
items.Add("bear", 100);
items.Add("lion", 50);

// Call OrderBy() method here on each item and provide them the IDs.
foreach (var item in items.OrderBy(k => k.Key))
{
    Console.WriteLine(item);// items are in sorted order
}

你可以做一个小技巧:

var sortedDictByOrder = items.OrderBy(v => v.Value);

or:

var sortedKeys = from pair in dictName
            orderby pair.Value ascending
            select pair;

这也取决于你存储的是什么类型的值:单个(如字符串,int)或多个(如列表,数组,用户定义的类)。 如果它是单个的,你可以把它列出来,然后应用排序。 如果它是用户定义的类,那么该类必须实现IComparable, ClassName: IComparable<ClassName>并覆盖compareTo(ClassName c),因为它们比LINQ更快,更面向对象。


所需的命名空间:使用System.Linq;

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

按描述排序:

foreach (KeyValuePair<string, int> kvp in counts.OrderByDescending(key => key.Value))
{
// some processing logic for each item if you want.
}

按Asc排序:

foreach (KeyValuePair<string, int> kvp in counts.OrderBy(key => key.Value))
{
// some processing logic for each item if you want.
}

分类打印:

var items = from pair in players_Dic
                orderby pair.Value descending
                select pair;

// Display results.
foreach (KeyValuePair<string, int> pair in items)
{
    Debug.Log(pair.Key + " - " + pair.Value);
}

将降序改为升序以改变排序顺序


字典根据定义是一种无序的关联结构,仅以可哈希的方式包含值和键。换句话说,没有一种可预见的方式来排序一本字典。

作为参考,请阅读这篇来自python语言的文章。

链接 Python数据结构


最好的方法:

var list = dict.Values.OrderByDescending(x => x).ToList();
var sortedData = dict.OrderBy(x => list.IndexOf(x.Value));

下面的代码片段按值对Dictionary进行排序。

代码首先创建一个字典,然后使用OrderBy方法对条目进行排序。

public void SortDictionary()  
{  
  
    // Create a dictionary with string key and Int16 value pair  
    Dictionary<string, Int16> AuthorList = new Dictionary<string, Int16>();  
    AuthorList.Add("Mahesh Chand", 35);  
    AuthorList.Add("Mike Gold", 25);  
    AuthorList.Add("Praveen Kumar", 29);  
    AuthorList.Add("Raj Beniwal", 21);  
    AuthorList.Add("Dinesh Beniwal", 84);   
  
    // Sorted by Value  
  
    Console.WriteLine("Sorted by Value");  
    Console.WriteLine("=============");  
    foreach (KeyValuePair<string, Int16> author in AuthorList.OrderBy(key => key.Value))  
    {  
        Console.WriteLine("Key: {0}, Value: {1}", author.Key, author.Value);  
    }  
}