890

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

有一个SortedList对单个值(比如频率)有好处的,我想映射回这个词。

SortedDictionary按键排序,而不是按值排序。有些人求助于自定义类,但有更清洁的方法吗?

4

20 回答 20

562

使用 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从句。

于 2008-08-04T15:22:03.867 回答
549

采用:

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));
于 2008-08-02T01:15:42.123 回答
320

你可以使用:

var ordered = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
于 2010-11-11T17:16:38.323 回答
173

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

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

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

于 2008-08-02T00:43:38.837 回答
169

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

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

当然,它可能不正确,但它确实有效。海仑定律意味着这很可能会继续有效。

于 2011-06-22T10:26:16.147 回答
64

在高层次上,您别无选择,只能浏览整个 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);
    }
);
于 2008-08-02T00:47:48.797 回答
27

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

于 2008-12-19T22:47:08.330 回答
22

您不对 Dictionary 中的条目进行排序。.NET 中的字典类被实现为一个哈希表——这个数据结构根据定义是不可排序的。

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

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

我不明白您为什么坚持在主/第一本词典中维护指向原始项目的链接。

如果您的集合中的对象具有更复杂的结构(更多字段),并且您需要能够使用几个不同的字段作为键来有效地访问/排序它们 - 您可能需要一个自定义数据结构,该结构将由主存储组成支持 O(1) 插入和删除 (LinkedList) 和几个索引结构 - 字典/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);
}
于 2012-12-13T06:19:09.490 回答
15

你可以使用:

Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
于 2015-07-20T11:01:19.383 回答
12

或者为了好玩,您可以使用一些 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));
于 2010-06-30T11:12:21.697 回答
10

使用 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>
于 2010-04-23T09:36:26.570 回答
6

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

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的一部分,但如果需要,您可以简单地将源代码复制到您自己的项目中。

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

于 2016-02-26T07:15:13.757 回答
5

实际上在 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);

或者:

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

它还取决于您存储的值类型:单个(如 string、int)或多个(如 List、Array、用户定义的类)。如果它是单一的,您可以列出它然后应用排序。
如果它是用户定义的类,那么该类必须实现 IComparableClassName: IComparable<ClassName>并重写compareTo(ClassName c),因为它们比 LINQ 更快且更面向对象。

于 2019-02-26T12:39:54.530 回答
3

获得排序字典的最简单方法是使用内置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

于 2010-04-02T22:36:32.783 回答
2

假设我们有一个字典

   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);
   sict.Add(768, 1011);

1)你可以使用temporary dictionary to store values as

        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);
        }
于 2015-02-02T10:46:01.693 回答
2

必需的命名空间:using 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.
}

按升序排序:

foreach (KeyValuePair<string, int> kvp in counts.OrderBy(key => key.Value))
{
// some processing logic for each item if you want.
}
于 2020-05-18T17:35:06.343 回答
1

排序和打印:

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

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

于 2020-11-15T06:30:08.923 回答
0

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

参考从python语言阅读这篇文章。

链接 python数据结构

于 2021-12-28T21:40:36.873 回答
-2

您可以按值对字典进行排序,并使用以下代码在字典中获取结果:

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
于 2012-07-24T12:24:01.903 回答
-2

鉴于您有一本字典,您可以使用下面的一个衬里直接按值对它们进行排序:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
于 2014-05-31T22:30:00.483 回答