你如何按价值对字典进行排序?

I often have to sort a dictionary, consisting of keys & values, by value. For example, I have a hash of words and respective frequencies, that I want to order by frequency.

有一个 SortedList 对单个值(比如说频率)很有用,我想将它映射回单词。

SortedDictionary orders by key, not value. Some resort to a custom class, but is there a cleaner way?

0
额外 编辑
意见: 2
除了对字典进行排序(就像在公认的答案中一样),您也可以创建一个执行技巧的 IComparer (它确实接受要比较的键,但使用键可以获得一个值)。 ;-)
额外 作者 BrainSlugs83,

17 答案

在高层次上,你没有其他选择,然后遍历整个词典并查看每个值。

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

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

List> myList = new List>(s);
myList.Sort(
    delegate(KeyValuePair firstPair,
    KeyValuePair nextPair)
    {
        return firstPair.Value.CompareTo(nextPair.Value);
    }
);
0
额外
stringnextPair - > string> nextPair stringfirstPair - > string> firstPair
额外 作者 Art,
完美的非Linq解决方案。即使在绝对不需要解决问题的情况下,人们仍然感到需要使用Linq,这一点让我惊叹不已。用C#3,我相信你也可以简化Sort来使用lambda:myList.Sort((x,y)=> x.Value.CompareTo(y.Value));
额外 作者 RobinHood70,

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

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

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

0
额外
这很方便。怎样才能颠倒走另一条路?
额外 作者 Dan Hastings,
@AndriusNaru?evi?ius:如果您将结果项目添加回字典中,您将销毁订单,因为字典不能保证以任何特定的方式订购
额外 作者 O. R. Mapper,
使用这种语法时,不要忘记添加System.Linq命名空间。
额外 作者 M. Dudley,
(for KeyValuePair item在keywordCounts.OrderBy(key => key.Value)中选择项目).ToDictionary(t => t.Key,t => t.Value) - 一个小的除了你的答案:)谢谢,btw :)
额外 作者 Andrius Naruševičius,
我试图在将KeyValuePair添加到ComboBox的同时对字典进行排序......这非常棒!谢谢!
额外 作者 Jason Down,

使用:

using System.Linq.Enumerable;
...
List> myList = aDictionary.ToList();

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

Since you're targeting .NET 2.0 or above, you can simplify this into lambda syntax -- it's equivalent, but shorter. If you're targeting .NET 2.0 you can only use this syntax if you're using the compiler from Visual Studio 2008 (or above).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
0
额外
它是一个班轮 - 你不需要大括号。它可以被重写为 myList.Sort((x,y)=> x.Value.CompareTo(y.Value));
额外 作者 Arnis Lapsa,
我可以向您推荐Skeet stackoverflow.com/a/2705623/41211
额外 作者 GONeale,
对不起,但这个答案很难理解,因为我不熟悉委托关键字(可能在vb中有所不同),n不清楚在哪里进行排序,因为您需要运行项数乘以项数(没有项目平方)通过搜索/比较每个元素到整个字典中的每个元素进行比较,或者如果您只是在当前n之间进行比较,那么您需要在集合中的多个循环中进行比较,就是为什么我没有像现在这样得到它。也许更多的信息排序重新排序发生在哪里会有帮助!
额外 作者 Erx_VB.NExT.Coder,
这个委托语句在排序方法中如何在VB.NET中查看?
额外 作者 Jonas Axelsson,
你们已经过度复杂了 - 一个字典已经实现了 IEnumerable ,所以你可以像这样得到一个排序列表: var mySortedList = myDictionary.OrderBy(d => d.Value)。 ToList(); </代码>
额外 作者 BrainSlugs83,
我使用了这个解决方案(谢谢!),但一直困惑了一会儿,直到我阅读Michael Stum的帖子(以及John Timney的代码片段),并意识到myList是次要对象,KeyValuePairs的列表,它是从字典创建的,然后排序。
额外 作者 Robin Bennett,
我知道这是两年后......但我确信这可以帮助某人代替以前的评论:myList.Sort(Function(firstPair As KeyValuePair(Of String,String),nextPair As KeyValuePair(Of String,String ))firstPair.Value.CompareTo(nextPair.Value))
额外 作者 sacredfaith,
在比较中对x和y进行降序排序:myList.Sort((x,y)=> y.Value.CompareTo(x.Value));
额外 作者 Arturo,
我认为值得注意的是这需要Linq作为ToList扩展方法。
额外 作者 Ben,

使用LINQ:

Dictionary myDict = new Dictionary();
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;

如果您使用的是 type-ahead 的词频索引,那么您还可以包含 type-ahead StartsWith 子句。

0
额外
请忽略 .ToDictionary 的所有建议 - 标准字典不保证排序顺序
额外 作者 AlexFoxGill,
对于那些使用.NET 2.0的人 - 您是否尝试过使用LINQBridge填补空白? albahari.com/nutshell/linqbridge.aspx
额外 作者 jocull,
@BorisB。我回滚到正确的版本。你也可以做到。任何人都可以编辑,使之成为更好的地方。 To all, ToDictionary 不是这个问题的正确答案,caryden的原始答案没有。快乐upvoting和un-downvoting。
额外 作者 nawfal,
很好的答案。而且,正如其他评论中提到的其他答案一样,一定要包含“using System.Linq;”在文件的顶部。否则,您会看到一些令人困惑的错误消息,而IntelliSense不起作用。
额外 作者 Mark Meuer,
返回类型应该是 IEnumerable > 或 。或者应该从头开始使用 SortedDictionary 。对于普通的 Dictionary ,MSDN明确指出“项目返回的顺序是未定义的。”。看起来@ rythos42的最新编辑是怪罪。 :)
额外 作者 Boris B.,
我如何将sortedDict改回字典?在这里发布新的SO问题: stackoverflow.com/questions/3066182/…
额外 作者 Kache,
可悲的是,这不适用于VS2005,因为那里有.net framework 2.0(没有LINQ)。 Bambrick的答案也是很好的。
额外 作者 Smalcat,
我不确定它是否总能正常工作,因为迭代字典并不能保证KeyValuePairs按照它们插入的顺序被“拉”。 Ergo,如果你在LINQ中使用orderby并不重要,因为Dictionary可以改变插入元素的顺序。它通常按预期工作,但没有任何保证,特别是对于大型字典。
额外 作者 Bozydar Sobczak,
我只是使用了一种简单的方法将其与其他最受好评的答案(使用 Stopwatch())进行比较,并使用LINQ将时间增加了近350% 。使用其他方法排序的四个(!)成员列表= 0.0039511秒; (相同)使用LINQ方法排序的四个成员列表= 0.0130195秒。
额外 作者 mbrownnyc,
var ordered = dict.OrderBy(x => x.Value);
0
额外
@theJerm:不正确
额外 作者 AlexFoxGill,
使用4.5框架,只是验证它不需要将字符串转换回字典。
额外 作者 Jagd,
我不知道为什么这个解决方案不是更受欢迎 - 也许是因为它需要.NET 3.5?
额外 作者 Contango,
因为它需要转换回字典,这并不总是直截了当的...
额外 作者 MoonKnight,
@theJerm通过将已排序的项目放回到字典中是否保证顺序?它今天可能有效,但不能保证。
额外 作者 nawfal,
这是一个很好的解决方案,但它应该在结束分号之前有这个权限:.ToDictionary(pair => pair.Key,pair => pair.Value);
额外 作者 theJerm,
我更喜欢这个,干净简单。 @Gravitas:我同意,OP中没有提及框架版本。
额外 作者 Andreas,
不应该将字典转换回字典,因为字典没有排序。无法保证KeyValuePairs将保持您想要的顺序。
额外 作者 David DeMar,

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

0
额外
@recursive任何字典都应该产生。有趣的是,我的答案是正确的,但不完整(可能已经做了更好的例子),它被投票在一个无效的答案下面,这将导致原始字典中重复值的例外(键是唯一的,值不能保证成为)
额外 作者 Roger Willcocks,
排序好的字典可以产生键值对的列表。
额外 作者 recursive,
这是bes的答案,因为Dictionary不可排序。它散列键,你可以执行一个非常快速的查找操作。
额外 作者 Paulius Zaliaduonis,

您可以按值对字典进行排序并将其保存回自己(以便在对其进行粗略处理时,值依次出现):

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

当然,这可能不是正确的,但它的工作原理。

0
额外
额外 作者 AlexFoxGill,
我认为这将工作,如果项目被同时添加到字典中,并且没有任何内容被删除/修改。有没有证据表明.NET会重新排序字典中的项目?
额外 作者 AaA,
字典输出不保证有任何特定的排序顺序。
额外 作者 Roger Willcocks,
这个“工作”不能保证。它的一个实现细节。它不需要在其他时间工作。错误的答案,downvoted。
额外 作者 nawfal,
我很担心在生产代码中看到这一点。这是不能保证的,可以随时更改。不是说我回避实用的解决方案,它只是表明对数据结构缺乏了解。
额外 作者 jamespconnor,
如果您想排序为降序列表,也可以使用OrderByDescending。
额外 作者 Mendokusai,
为我工作,但我不得不稍微改变它:Dictionary dict = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key,x => x.Value);
额外 作者 Josh,

鉴于你有一本字典,你可以使用下面的一行来直接对它们进行排序:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
0
额外
这个答案是不正确的,因为结果字典不能保证排序。
额外 作者 O. R. Mapper,

对使用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:


    
        
            
            
         
    

0
额外

The other answers are good, if you all you want is to have a "temporary" list sorted by Value. However, if you want to have a dictionary sorted by Key that automatically synchronizes with another dictionary that is sorted by Value, you could use the Bijection class.

Bijection allows you to initialize the collection with two existing dictionaries, so if you want one of them to be unsorted, and you want the other one to be sorted, you could create your bijection with code like

var dict = new Bijection(new Dictionary(), 
                               new SortedDictionary());

You can use dict like any normal dictionary (it implements IDictionary<>), and then call dict.Inverse to get the "inverse" dictionary which is sorted by Value.

Bijection is part of Loyc.Collections.dll, but if you want, you could simply copy the source code into your own project.

Note: In case there are multiple keys with the same value, you can't use Bijection, but you could manually synchronize between an ordinary Dictionary and a BMultiMap.

0
额外
类似于 http://stackoverflow.com/questions/268321 ,但可以用SortedDictionary替换每个Dictionary。虽然答案看起来不支持重复值(假设1到1)。
额外 作者 crokusek,

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

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

排序值

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

OrderBy子句 排序词典[C#]的程序

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

class Program
{
    static void Main()
    {
        // Example dictionary.
        var dictionary = new Dictionary(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 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
0
额外

您不要对词典中的条目进行排序。 .NET中的Dictionary类是作为散列表实现的 - 该数据结构不能按照定义进行排序。

如果你需要能够迭代你的集合(通过键) - 你需要使用SortedDictionary,它被实现为二进制搜索树。

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

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

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

您需要协调插入和删除操作,使索引与主集合(LinkedList)保持同步,并且删除操作会让我觉得非常昂贵。 这与数据库索引的工作方式类似 - 它们对于查找来说非常棒,但当您需要执行许多删除和删除操作时,它们将成为一种负担。

以上所有内容只有在您要查找大量处理时才是合理的。如果你只需要按频率排序就输出它们,那么你可以产生一个(匿名)元组列表:

var dict = new SortedDictionary();
// 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);
}
0
额外

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

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

sortedSections will contains the sorted version of sections

0
额外
@mbrownnyc - nope,这样做需要假设或先决条件,即VALUES是唯一的,这是不能保证的。
额外 作者 Roger Willcocks,
正如您在评论中提到的, SortedDictionary 按键排序。 OP想要按价值排序。在这种情况下, SortedDictionary 不起作用。
额外 作者 Marty Neal,
那么...如果他/她(你)可以,只需将值设置为键。我对操作进行了计时,并且 sorteddictionary()总是胜出至少1微秒,并且管理起来更容易(因为将它转换回与Dictionary类似的轻松交互和管理的开销是0(它已经是 sorteddictionary ))。
额外 作者 mbrownnyc,

您可以使用下面的代码按值排序字典并使用字典获得结果:

Dictionary <> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
0
额外
当你已经回答这个问题时,你为什么要添加这个答案?
额外 作者 nawfal,
通过将已排序的项目放回字典中,在枚举新字典时不再保证排序。
额外 作者 Marty Neal,

假设我们有一本字典

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

1)可以使用 临时字典将值存储为

        Dictionary dctTemp = new Dictionary();

        foreach (KeyValuePair pair in dict.OrderBy(key => key.Value))
        {
            dctTemp .Add(pair.Key, pair.Value);
        }
0
额外
Dictionary dic= new Dictionary();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
0
额外
也不正确。请参阅此处: stackoverflow.com/a/4007787/463828
额外 作者 Philipp M,