我经常需要根据值对字典(由键和值组成)进行排序。例如,我有一个单词和相应频率的散列,我想按频率排序。
有一个SortedList,它适用于单个值(比如频率),我想把它映射回单词。
SortedDictionary按键排序,而不是按值。有些人求助于自定义课程,但有没有更干净的方法呢?
我经常需要根据值对字典(由键和值组成)进行排序。例如,我有一个单词和相应频率的散列,我想按频率排序。
有一个SortedList,它适用于单个值(比如频率),我想把它映射回单词。
SortedDictionary按键排序,而不是按值。有些人求助于自定义课程,但有没有更干净的方法呢?
当前回答
在较高的层次上,您别无选择,只能遍历整个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);
}
);
其他回答
使用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>
环顾四周,使用一些c# 3.0特性,我们可以这样做:
foreach (KeyValuePair<string,int> item in keywordCounts.OrderBy(key=> key.Value))
{
// do something with item.Key and item.Value
}
这是我见过的最干净的方法,类似于Ruby处理散列的方法。
最好的方法:
var list = dict.Values.OrderByDescending(x => x).ToList();
var sortedData = dict.OrderBy(x => list.IndexOf(x.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);
}
使用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子句。